\PassOptionsToPackage{unicode=true}{hyperref} % options for packages loaded elsewhere
\PassOptionsToPackage{hyphens}{url}
\PassOptionsToPackage{dvipsnames,svgnames*,x11names*}{xcolor}
%
\documentclass[10pt,]{krantz}
\usepackage{lmodern}
\usepackage{amssymb,amsmath}
\usepackage{ifxetex,ifluatex}
\usepackage{fixltx2e} % provides \textsubscript
\ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0 % if pdftex
  \usepackage[T1]{fontenc}
  \usepackage[utf8]{inputenc}
  \usepackage{textcomp} % provides euro and other symbols
\else % if luatex or xelatex
  \usepackage{unicode-math}
  \defaultfontfeatures{Ligatures=TeX,Scale=MatchLowercase}
    \setmonofont[Mapping=tex-ansi,Scale=0.7]{Source Code Pro}
\fi
% use upquote if available, for straight quotes in verbatim environments
\IfFileExists{upquote.sty}{\usepackage{upquote}}{}
% use microtype if available
\IfFileExists{microtype.sty}{%
\usepackage[]{microtype}
\UseMicrotypeSet[protrusion]{basicmath} % disable protrusion for tt fonts
}{}
\IfFileExists{parskip.sty}{%
\usepackage{parskip}
}{% else
\setlength{\parindent}{0pt}
\setlength{\parskip}{6pt plus 2pt minus 1pt}
}
\usepackage{xcolor}
\usepackage{hyperref}
\hypersetup{
            pdftitle={JavaScript for R},
            pdfauthor={John Coene},
            colorlinks=true,
            linkcolor=Maroon,
            filecolor=Maroon,
            citecolor=Blue,
            urlcolor=Blue,
            breaklinks=true}
\urlstyle{same}  % don't use monospace font for urls
\usepackage{color}
\usepackage{fancyvrb}
\newcommand{\VerbBar}{|}
\newcommand{\VERB}{\Verb[commandchars=\\\{\}]}
\DefineVerbatimEnvironment{Highlighting}{Verbatim}{commandchars=\\\{\}}
% Add ',fontsize=\small' for more characters per line
\usepackage{framed}
\definecolor{shadecolor}{RGB}{248,248,248}
\newenvironment{Shaded}{\begin{snugshade}}{\end{snugshade}}
\newcommand{\AlertTok}[1]{\textcolor[rgb]{0.33,0.33,0.33}{#1}}
\newcommand{\AnnotationTok}[1]{\textcolor[rgb]{0.37,0.37,0.37}{\textbf{\textit{#1}}}}
\newcommand{\AttributeTok}[1]{\textcolor[rgb]{0.61,0.61,0.61}{#1}}
\newcommand{\BaseNTok}[1]{\textcolor[rgb]{0.06,0.06,0.06}{#1}}
\newcommand{\BuiltInTok}[1]{#1}
\newcommand{\CharTok}[1]{\textcolor[rgb]{0.5,0.5,0.5}{#1}}
\newcommand{\CommentTok}[1]{\textcolor[rgb]{0.37,0.37,0.37}{\textit{#1}}}
\newcommand{\CommentVarTok}[1]{\textcolor[rgb]{0.37,0.37,0.37}{\textbf{\textit{#1}}}}
\newcommand{\ConstantTok}[1]{\textcolor[rgb]{0,0,0}{#1}}
\newcommand{\ControlFlowTok}[1]{\textcolor[rgb]{0.27,0.27,0.27}{\textbf{#1}}}
\newcommand{\DataTypeTok}[1]{\textcolor[rgb]{0.27,0.27,0.27}{#1}}
\newcommand{\DecValTok}[1]{\textcolor[rgb]{0.06,0.06,0.06}{#1}}
\newcommand{\DocumentationTok}[1]{\textcolor[rgb]{0.37,0.37,0.37}{\textbf{\textit{#1}}}}
\newcommand{\ErrorTok}[1]{\textcolor[rgb]{0.14,0.14,0.14}{\textbf{#1}}}
\newcommand{\ExtensionTok}[1]{#1}
\newcommand{\FloatTok}[1]{\textcolor[rgb]{0.06,0.06,0.06}{#1}}
\newcommand{\FunctionTok}[1]{\textcolor[rgb]{0,0,0}{#1}}
\newcommand{\ImportTok}[1]{#1}
\newcommand{\InformationTok}[1]{\textcolor[rgb]{0.37,0.37,0.37}{\textbf{\textit{#1}}}}
\newcommand{\KeywordTok}[1]{\textcolor[rgb]{0.27,0.27,0.27}{\textbf{#1}}}
\newcommand{\NormalTok}[1]{#1}
\newcommand{\OperatorTok}[1]{\textcolor[rgb]{0.43,0.43,0.43}{\textbf{#1}}}
\newcommand{\OtherTok}[1]{\textcolor[rgb]{0.37,0.37,0.37}{#1}}
\newcommand{\PreprocessorTok}[1]{\textcolor[rgb]{0.37,0.37,0.37}{\textit{#1}}}
\newcommand{\RegionMarkerTok}[1]{#1}
\newcommand{\SpecialCharTok}[1]{\textcolor[rgb]{0,0,0}{#1}}
\newcommand{\SpecialStringTok}[1]{\textcolor[rgb]{0.5,0.5,0.5}{#1}}
\newcommand{\StringTok}[1]{\textcolor[rgb]{0.5,0.5,0.5}{#1}}
\newcommand{\VariableTok}[1]{\textcolor[rgb]{0,0,0}{#1}}
\newcommand{\VerbatimStringTok}[1]{\textcolor[rgb]{0.5,0.5,0.5}{#1}}
\newcommand{\WarningTok}[1]{\textcolor[rgb]{0.37,0.37,0.37}{\textbf{\textit{#1}}}}
\usepackage{longtable,booktabs}
% Fix footnotes in tables (requires footnote package)
\IfFileExists{footnote.sty}{\usepackage{footnote}\makesavenoteenv{longtable}}{}
\usepackage{graphicx,grffile}
\makeatletter
\def\maxwidth{\ifdim\Gin@nat@width>\linewidth\linewidth\else\Gin@nat@width\fi}
\def\maxheight{\ifdim\Gin@nat@height>\textheight\textheight\else\Gin@nat@height\fi}
\makeatother
% Scale images if necessary, so that they will not overflow the page
% margins by default, and it is still possible to overwrite the defaults
% using explicit options in \includegraphics[width, height, ...]{}
\setkeys{Gin}{width=\maxwidth,height=\maxheight,keepaspectratio}
\setlength{\emergencystretch}{3em}  % prevent overfull lines
\providecommand{\tightlist}{%
  \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
\setcounter{secnumdepth}{5}
% Redefines (sub)paragraphs to behave more like sections
\ifx\paragraph\undefined\else
\let\oldparagraph\paragraph
\renewcommand{\paragraph}[1]{\oldparagraph{#1}\mbox{}}
\fi
\ifx\subparagraph\undefined\else
\let\oldsubparagraph\subparagraph
\renewcommand{\subparagraph}[1]{\oldsubparagraph{#1}\mbox{}}
\fi

% set default figure placement to htbp
\makeatletter
\def\fps@figure{htbp}
\makeatother

\usepackage{booktabs}
\usepackage{longtable}
\usepackage[bf,singlelinecheck=off]{caption}

\usepackage{framed,color}
\definecolor{shadecolor}{RGB}{248,248,248}

\renewcommand{\textfraction}{0.05}
\renewcommand{\topfraction}{0.8}
\renewcommand{\bottomfraction}{0.8}
\renewcommand{\floatpagefraction}{0.75}

\renewenvironment{quote}{\begin{VF}}{\end{VF}}
\let\oldhref\href
\renewcommand{\href}[2]{#2\footnote{\url{#1}}}

\makeatletter
\newenvironment{kframe}{%
\medskip{}
\setlength{\fboxsep}{.8em}
 \def\at@end@of@kframe{}%
 \ifinner\ifhmode%
  \def\at@end@of@kframe{\end{minipage}}%
  \begin{minipage}{\columnwidth}%
 \fi\fi%
 \def\FrameCommand##1{\hskip\@totalleftmargin \hskip-\fboxsep
 \colorbox{shadecolor}{##1}\hskip-\fboxsep
     % There is no \\@totalrightmargin, so:
     \hskip-\linewidth \hskip-\@totalleftmargin \hskip\columnwidth}%
 \MakeFramed {\advance\hsize-\width
   \@totalleftmargin\z@ \linewidth\hsize
   \@setminipage}}%
 {\par\unskip\endMakeFramed%
 \at@end@of@kframe}
\makeatother

\renewenvironment{Shaded}{\begin{kframe}}{\end{kframe}}

\newenvironment{rmdblock}[1]
  {
  \begin{itemize}
  \renewcommand{\labelitemi}{
    \raisebox{-.7\height}[0pt][0pt]{
      {\setkeys{Gin}{width=3em,keepaspectratio}\includegraphics{images/#1}}
    }
  }
  \setlength{\fboxsep}{1em}
  \begin{kframe}
  \item
  }
  {
  \end{kframe}
  \end{itemize}
  }
\newenvironment{rmdnote}
  {\begin{rmdblock}{note}}
  {\end{rmdblock}}
\newenvironment{rmdcaution}
  {\begin{rmdblock}{caution}}
  {\end{rmdblock}}
\newenvironment{rmdimportant}
  {\begin{rmdblock}{important}}
  {\end{rmdblock}}
\newenvironment{rmdtip}
  {\begin{rmdblock}{tip}}
  {\end{rmdblock}}
\newenvironment{rmdwarning}
  {\begin{rmdblock}{warning}}
  {\end{rmdblock}}

\usepackage{makeidx}
\makeindex

\urlstyle{tt}

\usepackage{amsthm}
\makeatletter
\def\thm@space@setup{%
  \thm@preskip=8pt plus 2pt minus 4pt
  \thm@postskip=\thm@preskip
}
\makeatother

\usepackage{float}

\frontmatter
\usepackage[]{natbib}
\bibliographystyle{apalike}

\title{JavaScript for R}
\author{John Coene}
\date{2021-04-22}

\begin{document}
\maketitle

% you may need to leave a few empty pages before the dedication page

%\cleardoublepage\newpage\thispagestyle{empty}\null
%\cleardoublepage\newpage\thispagestyle{empty}\null
%\cleardoublepage\newpage
\thispagestyle{empty}

\begin{center}
%\includegraphics{images/dedication.pdf}
\end{center}

\setlength{\abovedisplayskip}{-5pt}
\setlength{\abovedisplayshortskip}{-5pt}

{
\hypersetup{linkcolor=}
\setcounter{tocdepth}{2}
\tableofcontents
}
\listoffigures
\hypertarget{preface}{%
\chapter*{Preface}\label{preface}}


The R programming language has seen the integration of many languages; C, C++, Python, to name a few, can be seamlessly embedded into R so one can conveniently call code written in other languages from the R console. Little known to many, R works just as well with JavaScript---this book delves into the various ways both languages can work together.

The ultimate aim of this work is to demonstrate to readers the many great benefits can reap by inviting JavaScript into their data science workflow. In that respect, the book is not teaching one JavaScript but instead demonstrates how little JavaScript can significantly support and enhance R code. Therefore, the focus is on integrating external JavaScript libraries and only limited knowledge of JavaScript is required in order to learn from the book. Moreover, the book focuses on generalisable learnings so the reader can transfer takeaways from the book to solve real-world problems.

Throughout the book, several Shiny applications and R packages are put together as examples. All of these, along with the code for the entire book, can be found on the GitHub repository: \href{https://github.com/JohnCoene/javascript-for-r}{github.com/JohnCoene/javascript-for-r}.

\hypertarget{premise}{%
\section*{Premise}\label{premise}}


The R programming language has been propelled into web browsers with the introduction of packages such as \href{https://shiny.rstudio.com/}{Shiny} \citep{R-shiny} and \href{https://rmarkdown.rstudio.com/}{rmarkdown} \citep{R-rmarkdown} which have greatly improved how R users can communicate complex insights by building interactive web applications and interactive documents. Yet most R developers are not familiar with one of web browsers' core technology: JavaScript. This book aims to remedy that by revealing how much JavaScript can greatly enhance various stages of data science pipelines from the analysis to the communication of results.

Notably, the focus of the book truly is the integration of JavaScript with R, where both languages either actively interact with one another, or where JavaScript enables doing things otherwise not accessible to R users. It is not merely about including JavaScript code that works alongside R.

\hypertarget{book-structure}{%
\section*{Book Structure}\label{book-structure}}


\begin{enumerate}
\def\labelenumi{\arabic{enumi}.}
\item
  The book opens with an introduction to illustrate its premise better it provides rationales for using JavaScript in conjunction with R, which it supports with existing R packages that use JavaScript and are available on CRAN. Then it briefly describes concepts essential to understanding the rest of the book to ensure the reader can follow along. Finally, this part closes by listing the various methods with which one might make JavaScript work with R.
\item
  We explore existing integrations of JavaScript and R namely by exploring packages to grasp how these tend to work and the interface to JavaScript they provide.
\item
  A sizeable part of the book concerns data visualisation it plunges into creating interactive outputs with the htmlwidgets package. This opens with a brief overview of how it works and libraries that make great candidates to integrate with the htmlwidgets package. Then a first, admittedly unimpressive, widget is built to look under the hood and observe the inner workings of such outputs to grasp a better understanding of how htmlwidgets work. Next, we tackle a more substantial library that allows drawing arcs between countries on a 3D globe, which we cover in great depth. The last two chapters go into more advanced topics, such as security and resizing.
\item
  The fourth part of the book details how JavaScript can work with Shiny. Once the basics are out of the way, the second chapter builds the first utility to display notifications programmatically. Then we create a Shiny application that runs an image classification algorithm in the browser. This is then followed by the creation of custom Shiny inputs and outputs. Finally, Shiny and htmlwidgets are (literally) connected by including additional functionalities in interactive visualisations when used with the Shiny framework.
\item
  Then the book delves into using JavaScript for computations, namely via the V8 engine and Node.js. After a short introduction, chapters will walk the reader through various examples: a fuzzy search, a time format converter, and some basic natural language operations.
\item
  Finally, we look at how one can use some of the more modern JavaScript technologies such as Vue\index{Vue}, React, and webpack with R---these can make the use of JavaScript more agile and robust.
\item
  Next the book closes with examples of all the integrations explored previously. This involves recreating (a part of) the plotly package, building an image classifier, adding progress bars to a Shiny application, building an app with HTTP cookies, and running basic machine learning operations in JavaScript.
\item
  Finally, the book concludes with some noteworthy remarks on where to go next.
\end{enumerate}

\hypertarget{acknowledgement}{%
\section*{Acknowledgement}\label{acknowledgement}}


Many people in the R community have inspired me and provided the knowledge to write this book, amongst them ultimately are \href{https://github.com/ramnathv/}{Ramnath Vaidyanathan,} for his amazing work on the htmlwidgets \citep{R-htmlwidgets} package \href{https://github.com/timelyportfolio}{Kent Russell,} from whom I have learned a lot via his work on making Vue and React accessible in R and \href{https://github.com/cpsievert}{Carson Sievert,} for pioneering probably the most popular integration of R and JavaScript with the plotly \citep{R-plotly} package.

Early reviewers also shared precious feedback that helped make the book dramatically better, thanks to \href{@mayacelium}{Maya Gans,} \href{@felipe_mattioni}{Felipe Mattioni Maturana,} and \href{@Wei_Su}{Wei Su} for thoroughly going through every line of the book.

Thanks to \href{https://www.davisuko.com/}{Cody Davis} for the cover image of the book.

\mainmatter

\hypertarget{part-basics-and-roadmap}{%
\part{Basics and Roadmap}\label{part-basics-and-roadmap}}

\hypertarget{intro-overview}{%
\chapter{Overview}\label{intro-overview}}

This book starts with a rationale for integrating JavaScript with R and supports it with examples, namely packages that use JavaScript and are available on CRAN\index{CRAN}. Then, we list the various ways in which one might go about making both languages work together. In the next chapter, we go over prerequisites and a review of concepts fundamental to fully understand the more advanced topics residing in the forthcoming chapters.

\hypertarget{intro-overview-rationale}{%
\section{Rationale}\label{intro-overview-rationale}}

Why blend two languages seemingly so far removed from each other? Well, precisely because they are fundamentally different languages that each have their strengths and weaknesses; combining the two allows making the most of their consolidated advantages and circumvents their respective limitations to produce software altogether better for it.

Nevertheless, a fair reason to use JavaScript might be that the thing one wants to achieve in R has already been realised in JavaScript. Why reinvent the wheel when the solution already exists and that it can be made accessible from R? The R package \href{https://github.com/ateucher/rmapshaper}{rmapshaper} \citep{R-rmapshaper} by Andy Teucher that integrates \href{https://github.com/mbloch/mapshaper/}{mapshaper,} a library to edit geo-spatial-related files such as GeoJSON, or TopoJSON. JavaScript is by no means required to make those computations; they could be rewritten solely in R, but that would be vastly more laborious than wrapping the JavaScript API in R as done by the package rmapshaper.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(rmapshaper)}

\CommentTok{# get data}
\KeywordTok{data}\NormalTok{(states, }\DataTypeTok{package =} \StringTok{"geojsonio"}\NormalTok{)}

\NormalTok{states_json <-}\StringTok{ }\NormalTok{geojsonio}\OperatorTok{::}\KeywordTok{geojson_json}\NormalTok{(}
\NormalTok{  states, }
  \DataTypeTok{geometry =} \StringTok{"polygon"}\NormalTok{, }
  \DataTypeTok{group =} \StringTok{"group"}
\NormalTok{)}
\CommentTok{#> Registered S3 method overwritten by 'geojsonsf':}
\CommentTok{#>   method        from   }
\CommentTok{#>   print.geojson geojson}
\CommentTok{#> Assuming 'long' and 'lat' are longitude and latitude, respectively}

\NormalTok{states_sp <-}\StringTok{ }\NormalTok{geojsonio}\OperatorTok{::}\KeywordTok{geojson_sp}\NormalTok{(states_json)}

\CommentTok{# print shape file size}
\KeywordTok{print}\NormalTok{(}\KeywordTok{object.size}\NormalTok{(states_sp), }\DataTypeTok{units =} \StringTok{"Mb"}\NormalTok{)}
\CommentTok{#> 0.4 Mb}

\CommentTok{# simplify with rmapshaper}
\NormalTok{states_sm <-}\StringTok{ }\NormalTok{rmapshaper}\OperatorTok{::}\KeywordTok{ms_simplify}\NormalTok{(states_sp, }\DataTypeTok{keep =} \FloatTok{0.05}\NormalTok{)}

\CommentTok{# print reduced size}
\KeywordTok{print}\NormalTok{(}\KeywordTok{object.size}\NormalTok{(states_sm), }\DataTypeTok{units =} \StringTok{"Mb"}\NormalTok{)}
\CommentTok{#> 0.2 Mb}
\end{Highlighting}
\end{Shaded}

Another great reason is that JavaScript can do things that R cannot, e.g., run in the browser. Therefore, one cannot natively create interactive visualisations with R. \href{https://plotly-r.com/}{Plotly} \citep{R-plotly} by Carson Sievert packages the \href{https://plot.ly/}{plotly JavaScript library} to let one create interactive visualisations solely from R code as shown in Figure \ref{fig:plotly-basic-example}.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(plotly)}

\KeywordTok{plot_ly}\NormalTok{(diamonds, }\DataTypeTok{x =} \OperatorTok{~}\NormalTok{cut, }\DataTypeTok{color =} \OperatorTok{~}\NormalTok{clarity, }\DataTypeTok{width =} \StringTok{"100%"}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/01-plotly} 

}

\caption{Basic htmlwidget example}\label{fig:plotly-basic-example}
\end{figure}

Finally, JavaScript can work together with R to improve how we communicate insights. One of the many ways in which Shiny stands out is that it lets one create web applications solely from R code with no knowledge of HTML, CSS, or JavaScript, but that does not mean they can't extend Shiny---quite the contrary. The \href{http://waiter.john-coene.com/}{waiter package} \citep{R-waiter} integrates a variety of JavaScript libraries to display loading screens in Shiny applications as in Figure \ref{fig:intro-waiter}.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(shiny)}
\KeywordTok{library}\NormalTok{(waiter)}

\NormalTok{ui <-}\StringTok{ }\KeywordTok{fluidPage}\NormalTok{(}
  \KeywordTok{use_waiter}\NormalTok{(), }\CommentTok{# include dependencies}
  \KeywordTok{actionButton}\NormalTok{(}\StringTok{"show"}\NormalTok{, }\StringTok{"Show loading for 3 seconds"}\NormalTok{)}
\NormalTok{)}

\NormalTok{server <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(input, output, session)\{}
  \CommentTok{# create a waiter}
\NormalTok{  w <-}\StringTok{ }\NormalTok{Waiter}\OperatorTok{$}\KeywordTok{new}\NormalTok{()}

  \CommentTok{# on button click}
  \KeywordTok{observeEvent}\NormalTok{(input}\OperatorTok{$}\NormalTok{show, \{}
\NormalTok{    w}\OperatorTok{$}\KeywordTok{show}\NormalTok{()}
    \KeywordTok{Sys.sleep}\NormalTok{(}\DecValTok{3}\NormalTok{)}
\NormalTok{    w}\OperatorTok{$}\KeywordTok{hide}\NormalTok{()}
\NormalTok{  \})}
\NormalTok{\}}

\KeywordTok{shinyApp}\NormalTok{(ui, server)}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/waiter} 

}

\caption{Waiter screen}\label{fig:intro-waiter}
\end{figure}

Hopefully this makes a couple of great reasons and alluring examples to entice the reader to persevere with this book.

\hypertarget{intro-methods}{%
\section{Methods}\label{intro-methods}}

Though perhaps not evident at first, all of the packages used as examples in the previous section interfaced with R very differently. As we'll discover, there are many ways in which one can blend JavaScript with R. Generally the way to go about it is dictated by the nature of what is to be achieved.

Let's list the methods available to us to blend JavaScript with R before covering each of them in-depth in their own respective chapter later in the book.

\hypertarget{intro-v8}{%
\subsection{V8}\label{intro-v8}}

\href{https://github.com/jeroen/v8}{V8} by Jeroen Ooms is an R interface to Google's JavaScript engine. It will let you run JavaScript code directly from R and get the result back; it even comes with an interactive console. This is the way the rmapshaper package used in a previous example internally interfaces with the turf.js library.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(V8)}

\NormalTok{ctx <-}\StringTok{ }\KeywordTok{v8}\NormalTok{()}

\NormalTok{ctx}\OperatorTok{$}\KeywordTok{eval}\NormalTok{(}\StringTok{"2 + 2"}\NormalTok{) }\CommentTok{# this is evaluated in JavaScript!}
\CommentTok{#> [1] "4"}
\end{Highlighting}
\end{Shaded}

\hypertarget{intro-htmlwidgets}{%
\subsection{htmlwidgets}\label{intro-htmlwidgets}}

\href{http://www.htmlwidgets.org/}{htmlwidgets} \citep{R-htmlwidgets} specialises in wrapping JavaScript libraries that generate visual outputs. This is what packages such as plotly, \href{https://rstudio.github.io/DT/}{DT} \citep{R-DT}, \href{http://jkunst.com/highcharter/}{highcharter} \citep{R-highcharter}, and many more use to provide interactive visualisation with R.

It is by far the most popular integration out there: at the time of writing it has been downloaded nearly 10 million times from \index{CRAN}. It will therefore be covered extensively in later chapters.

\hypertarget{intro-shiny}{%
\subsection{Shiny}\label{intro-shiny}}

The Shiny framework allows creating applications accessible from web browsers\index{web browser} where JavaScript natively runs; it follows that JavaScript can run \emph{alongside} such applications. Often overlooked though, the two can also work \emph{hand-in-hand} as one can pass data from the R server to the JavaScript front end and vice versa. This is how the previously-mentioned package waiter internally works with R.

\hypertarget{intro-amiss}{%
\section{Methods Amiss}\label{intro-amiss}}

Note that there are also two other prominent ways one can use JavaScript with R that are not covered in this book. The main reason being that they require significant knowledge of specific JavaScript libraries, d3.js and React, and while these are themselves advanced uses of JavaScript, their integration with R via the following listed packages are relatively straightforward.

\hypertarget{intro-reactr-vuer}{%
\subsection{reactR \& vueR}\label{intro-reactr-vuer}}

\href{https://react-r.github.io/reactR/}{ReactR} \citep{R-reactR} is an R package that emulates very well htmlwidgets but specifically for the \href{https://reactjs.org/}{React\index{React} framework}. Unlike htmlwidgets, it is not limited to visual outputs and also provides functions to build inputs, e.g., a drop-down menu (like \texttt{shiny::selectInput}). The \href{https://glin.github.io/reactable/}{reactable package} \citep{R-reactable} uses reactR to enable building interactive tables solely from R code as shown in Figure \ref{fig:reactable-example}.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{reactable}\OperatorTok{::}\KeywordTok{reactable}\NormalTok{(iris[}\DecValTok{1}\OperatorTok{:}\DecValTok{5}\NormalTok{, ], }\DataTypeTok{showPagination =} \OtherTok{TRUE}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/01-reactable} 

}

\caption{reactable package example}\label{fig:reactable-example}
\end{figure}

There is also the package vueR \citep{R-vueR}, which brings some of \index{Vue}Vue to R.

\hypertarget{intro-r2d3}{%
\subsection{r2d3}\label{intro-r2d3}}

\href{https://rstudio.github.io/r2d3/}{r2d3} \citep{R-r2d3} by RStudio is an R package designed specifically to work with \href{https://d3js.org/}{d3.js}. It is similar to htmlwidgets but works rather differently, it allows create visualisations such as Figure \ref{fig:r2d3}.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# https://rstudio.github.io/r2d3/articles/gallery/chord/}
\NormalTok{r2d3}\OperatorTok{::}\KeywordTok{r2d3}\NormalTok{(}
  \DataTypeTok{data =} \KeywordTok{matrix}\NormalTok{(}\KeywordTok{round}\NormalTok{(}\KeywordTok{runif}\NormalTok{(}\DecValTok{16}\NormalTok{, }\DecValTok{1}\NormalTok{, }\DecValTok{10000}\NormalTok{)), }\DataTypeTok{ncol =} \DecValTok{4}\NormalTok{, }\DataTypeTok{nrow =} \DecValTok{4}\NormalTok{), }
  \DataTypeTok{script =} \StringTok{"chord.js"}
\NormalTok{)}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/01-d3} 

}

\caption{r2d3 basic example}\label{fig:r2d3}
\end{figure}

\hypertarget{prerequisites}{%
\chapter{Prerequisites}\label{prerequisites}}

The code contained in the following pages is approachable to readers with basic knowledge of R. Still, familiarity with package development using \href{https://devtools.r-lib.org/}{devtools} \citep{R-devtools}, the \href{https://shiny.rstudio.com/}{Shiny} framework \citep{R-shiny}, the JSON data format, and JavaScript are essential.

The reason for the former is that some of the ways one builds integrations with JavaScript naturally take the form of R packages. Also, R packages make sharing code, datasets, and anything else R-related extremely convenient, they come with a relatively strict structure, the ability to run unit tests, and much more. These have thus become a core feature of the R ecosystem and, therefore, are used extensively in the book as we create several packages. Therefore, the following section runs over the essentials of building a package to ensure everyone can keep up.

Then we briefly go through the JSON data format as it will be used to a great extent to communicate between R and JavaScript. Since both Shiny and JavaScript run in the browser\index{web browser} they make for axiomatic companions; we'll therefore use Shiny\index{Shiny} extensively. Finally, there is an obligatory short introduction to JavaScript.

It is highly recommended to use the freely available \href{https://rstudio.com/products/rstudio/}{RStudio IDE}\index{RStudio} to follow along as it makes a lot of things easier down the line.

\hypertarget{basics-package-dev}{%
\section{R Package Development}\label{basics-package-dev}}

Developing R packages used to be notoriously tricky, but things have considerably changed in recent years, namely thanks to the devtools \citep{R-devtools}, roxygen2 \citep{R-roxygen2}, and more recent \href{https://usethis.r-lib.org/}{usethis} \citep{R-usethis} packages. Devtools is short for ``developer tools,'' it is specifically designed to help creating packages; setting up tests, running checks, building and installing packages, etc. The second provides an all too convenient way to generate the documentation of packages, and usethis, more broadly, helps setting up projects, and automating repetitive tasks. Here, we only skim over the fundamentals, there is an entire book by Hadley Wickham called \href{http://r-pkgs.had.co.nz/}{\emph{R Packages}} solely dedicated to the topic.

Start by installing those packages from CRAN\index{CRAN} the roxygen2 package does not need to be explicitly installed as it is a dependency\index{dependency} of devtools.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{install.packages}\NormalTok{(}\KeywordTok{c}\NormalTok{(}\StringTok{"devtools"}\NormalTok{, }\StringTok{"usethis"}\NormalTok{))}
\end{Highlighting}
\end{Shaded}

\hypertarget{basics-create-pkg}{%
\subsection{Creating a Package}\label{basics-create-pkg}}

There are multiple ways to create a package. One could manually create every file, use the RStudio IDE\index{RStudio}, or create it from the R console with the usethis \citep{R-usethis} package.

From the RStudio IDE\index{RStudio} go to \texttt{File\ \textgreater{}\ New\ Project\ \textgreater{}\ New\ Directory\ \textgreater{}\ R\ Package} then select ``R package'' and fill in the small form, namely name the package and specify the directory where it should be created, as shown in Figure \ref{fig:rstudio-create-package}.

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/rstudio-create-package} 

}

\caption{Package creation wizard}\label{fig:rstudio-create-package}
\end{figure}

But it could be argued that it's actually more accessible from the R console with the usethis package. The \texttt{create\_package} function takes as first argument the path to create the package. If you run it from RStudio\index{RStudio} a new project window should open.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# creates a package named "test" in root of directory.}
\NormalTok{usethis}\OperatorTok{::}\KeywordTok{create_package}\NormalTok{(}\StringTok{"test"}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

\begin{verbatim}
✔ Creating 'test/'
✔ Setting active project to '/Packages/test'
✔ Creating 'R/'
✔ Writing 'DESCRIPTION'
Package: test
Title: What the Package Does (One Line, Title Case)
Version: 0.0.0.9000
Authors@R (parsed):
    * First Last <first.last@example.com> [aut, cre] (YOUR-ORCID-ID)
Description: What the package does (one paragraph).
License: `use_mit_license()`, `use_gpl3_license()` or friends to
    pick a license
Encoding: UTF-8
LazyData: true
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.1.1.9000
✔ Writing 'NAMESPACE'
✔ Changing working directory to 'test/'
✔ Setting active project to '<no active project>'
\end{verbatim}

\hypertarget{basics-metadata}{%
\subsection{Metadata}\label{basics-metadata}}

Every R package includes a \texttt{DESCRIPTION} file which includes metadata about the package. This includes a range of things like the license defining who can use the package, the name of the package, its dependencies\index{dependency}, and more. Below is the default created by the usethis package with \texttt{usethis::create\_package("test")}.

\begin{verbatim}
Package: test
Title: What the Package Does (One Line, Title Case)
Version: 0.0.0.9000
Authors@R: 
    person(given = "First",
           family = "Last",
           role = c("aut", "cre"),
           email = "first.last@example.com",
           comment = c(ORCID = "YOUR-ORCID-ID"))
Description: What the package does (one paragraph).
License: `use_mit_license()`, `use_gpl3_license()` or friends to
    pick a license
Encoding: UTF-8
LazyData: true
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.1.1.9000
\end{verbatim}

Much of this is outside the scope of the book. However, it is good to grasp how dependencies are specified. As packages are generally intended for sharing with others, it is vital to ensure users of the package meet the dependencies\index{dependency}; otherwise, the package may not work in places. For instance, were we to create a package that relies on one or more functions from the stringr \citep{R-stringr} package we would need to ensure people who install the package have it installed on their machine or those functions will not work.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# R/string.R}
\NormalTok{string_length <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(string) \{}
\NormalTok{  stringr}\OperatorTok{::}\KeywordTok{str_length}\NormalTok{(string)}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

\begin{rmdnote}
Note that the function is preceded by its namespace with \texttt{::}
(more on this later).
\end{rmdnote}

The \texttt{DESCRIPTION} file does this; it will make sure that the dependencies\index{dependency} of the package are met by users who install it. We can specify such dependencies\index{dependency} under \texttt{Imports}, where we can list packages required separated by a comma.

\begin{verbatim}
Imports:
  stringr,
  dplyr
\end{verbatim}

Then again, the usethis package also allows doing so consistently from the R console, which is great to avoid mishandling the \texttt{DESCRIPTION} file.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# add stringr under Imports}
\NormalTok{usethis}\OperatorTok{::}\KeywordTok{use_package}\NormalTok{(}\StringTok{'stringr'}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

One can also specify another type of dependencies\index{dependency} under \texttt{Suggests}, other packages that enhance the package but are not required to run it. These, unlike package under \texttt{Imports}, are not automatically installed if missing, which can greatly reduce overhead.

\hypertarget{basics-r-code}{%
\subsection{R code}\label{basics-r-code}}

An R package must follow a strict structure. R code must be placed in an \texttt{R/} directory so one should only find \texttt{.R} files in that directory. These files generally contain functions, methods, and R objects.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# R/add.R}
\NormalTok{string_length <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(strings) \{}
\NormalTok{  stringr}\OperatorTok{::}\KeywordTok{str_length}\NormalTok{(strings)}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

\hypertarget{basics-documentation}{%
\subsection{Documentation}\label{basics-documentation}}

Documenting packages used to be notoriously complicated, but thanks to the package roxygen2 that is no longer the case. The documentation of functions of the package (accessible with \texttt{?}) and datasets that comprise the package reside in separate files sitting in the \texttt{man/} directory. These are \texttt{.Rd} files that use a custom syntax resembling LaTex. The roxygen package eases the creation of these files by turning special comments and tags in \texttt{.R} files into said \texttt{.Rd} files.

Special comments are a standard R comment \texttt{\#} followed by an apostrophe \texttt{\textquotesingle{}}. The first sentence of the documentation is the title of the documentation file while the second is the description.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{#' Strings Length}
\CommentTok{#' }
\CommentTok{#' Returns the number of characters in strings. }
\NormalTok{string_length <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(strings) \{}
\NormalTok{  stringr}\OperatorTok{::}\KeywordTok{str_length}\NormalTok{(strings)}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

There are a plethora of roxygen2 tags to further document different sections. Below we use two different tags to document the parameters and give an example.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{#' Strings Length}
\CommentTok{#' }
\CommentTok{#' Returns the number of characters in strings. }
\CommentTok{#' }
\CommentTok{#' @param strings A vector of character strings.}
\CommentTok{#' }
\CommentTok{#' @example string_length(c("hello", "world"))}
\NormalTok{string_length <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(strings) \{}
\NormalTok{  stringr}\OperatorTok{::}\KeywordTok{str_length}\NormalTok{(strings)}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

As well as generating documentation, the roxygen2 package also allows populating the \texttt{NAMESPACE} file. This is an extensive and often confusing topic, but for this book, we'll be content with the following: the \texttt{NAMESPACE} includes functions that are \emph{imported} and \emph{exported}\index{export} by the package.

By default, functions that are present in the R files in the \texttt{R/} directory are not exported: they are not accessible outside the package. Therefore the \texttt{string\_length} function defined previously will not be made available to users of the package, only other functions within the package will be able to call it. To export it we can use the \texttt{@export} tag\index{export}. This will place the function as exported in the \texttt{NAMESPACE} file.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{#' Strings Length}
\CommentTok{#' }
\CommentTok{#' Returns the number of characters in strings. }
\CommentTok{#' }
\CommentTok{#' @param strings A vector of character strings.}
\CommentTok{#' }
\CommentTok{#' @example string_length(c("hello", "world"))}
\CommentTok{#' }
\CommentTok{#' @export}
\NormalTok{string_length <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(strings) \{}
\NormalTok{  stringr}\OperatorTok{::}\KeywordTok{str_length}\NormalTok{(strings)}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

There are two ways to use external functions (functions from other R packages), as done thus far in the \texttt{string\_length} function by using the namespace (package name) to call the function: \texttt{stringr::str\_length}. Or by importing the function needed using a roxygen2 tag thereby removing the need for using the namespace.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{#' Strings Length}
\CommentTok{#' }
\CommentTok{#' Returns the number of characters in strings. }
\CommentTok{#' }
\CommentTok{#' @param strings A vector of character strings.}
\CommentTok{#' }
\CommentTok{#' @example string_length(c("hello", "world"))}
\CommentTok{#' }
\CommentTok{#' @importFrom stringr str_length}
\CommentTok{#' }
\CommentTok{#' @export}
\NormalTok{string_length <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(strings) \{}
  \KeywordTok{str_length}\NormalTok{(strings) }\CommentTok{# namespace removed}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

Above we import the function \texttt{str\_length} from the \texttt{stringr} package using the \texttt{importFrom} roxygen2 tag. The first term following the tag is the name of the package wherefrom to import the functions, and the following terms are the name of the functions separated by spaces so one can import multiple functions from the same package with, e.g.: \texttt{@importFrom\ stringr\ str\_length\ str\_to\_upper}. If the package imports many functions from a single package one might also consider importing the package in its entirety with, e.g.: \texttt{@import\ stringr}.

Finally, one can actually generate the \texttt{.Rd} documentation files and populate the \texttt{NAMESPACE} with either the \texttt{devtools::document()} function or \texttt{roxygen2::roxygenise()}.

\begin{rmdnote}
Remember to run \texttt{devtools::document()} after changing roxygen2
tags otherwise changes are not actually reflected in the
\texttt{NAMESPACE} and documentation.
\end{rmdnote}

\hypertarget{basics-installed-files}{%
\subsection{Installed files}\label{basics-installed-files}}

Here we tackle the topic of installed files as it will be relevant to much of what the book covers. Installed files are files that are downloaded and copied as-is when users install the package. This directory will therefore come in very handy to store JavaScript files that package will require. These files can be accessed with the \texttt{system.file} function, which will look for a file from the root of the \texttt{inst/} directory.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# return path to `inst/dependency.js` in `myPackage`}
\NormalTok{path <-}\StringTok{ }\KeywordTok{system.file}\NormalTok{(}\StringTok{"dependency.js"}\NormalTok{, }\DataTypeTok{package =} \StringTok{"myPackage"}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

\hypertarget{basics-build-load-install}{%
\subsection{Build, load, and install}\label{basics-build-load-install}}

Finally, after generating the documentation of the package with \texttt{devtools::document()} one can install it locally with \texttt{devtools::install()}. This, however, can take a few seconds too many whilst developing a package as one iterates and regularly tries things; \texttt{devtools::load\_all()} will not install the package but load all the functions and object in the global environment\index{environment} to let you run them.

There is some cyclical nature to developing packages:

\begin{enumerate}
\def\labelenumi{\arabic{enumi}.}
\tightlist
\item
  Write some code
\item
  Run \texttt{devtools::document()} (if documentation tags have changed)
\item
  Run \texttt{devtools::load\_all()}
\item
  Repeat
\end{enumerate}

Note whilst this short guide will help you develop packages good enough for your system it will certainly not pass \index{CRAN} checks.

\hypertarget{basics-json}{%
\section{JSON}\label{basics-json}}

JSON\index{JSON} (JavaScript Object Notation) is a prevalent data \emph{interchange} format with which we will work extensively throughout this book; it is thus crucial that we have a good understanding of it before we plunge into the nitty-gritty. As one might foresee, if we want two languages to work together, we must have a data format that can be understood by both---JSON\index{JSON} lets us harmoniously pass data from one to the other. While it is natively supported in JavaScript, it can be graciously handled in R with the \href{https://CRAN.R-project.org/package=jsonlite}{jsonlite package} \citep{R-jsonlite} it is the serialiser used internally by all R packages that we explore in this book.

\begin{rmdnote}
``To serialise''\index{serialise} is just jargon for converting data to
JSON.
\end{rmdnote}

\hypertarget{serialising}{%
\subsection{Serialising}\label{serialising}}

JSON\index{JSON} is to all intents and purposes the equivalent of lists in R; a flexible data format that can store pretty much anything--except data.frames, a structure that does not exist in JavaScript. Below we create a nested list and convert it to JSON\index{JSON} with the help of jsonlite. We set \texttt{pretty} to \texttt{TRUE} to add indentation for cleaner printing, but this is an argument you should omit when writing production code; it will reduce the file size (fewer spaces = smaller file size).

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# install.packages("jsonlite")}
\KeywordTok{library}\NormalTok{(jsonlite)}

\NormalTok{lst <-}\StringTok{ }\KeywordTok{list}\NormalTok{(}
  \DataTypeTok{a =} \DecValTok{1}\NormalTok{,}
  \DataTypeTok{b =} \KeywordTok{list}\NormalTok{(}
    \DataTypeTok{c =} \KeywordTok{c}\NormalTok{(}\StringTok{"A"}\NormalTok{, }\StringTok{"B"}\NormalTok{)}
\NormalTok{  ),}
  \DataTypeTok{d =} \DecValTok{1}\OperatorTok{:}\DecValTok{5}
\NormalTok{)}

\KeywordTok{toJSON}\NormalTok{(lst, }\DataTypeTok{pretty =} \OtherTok{TRUE}\NormalTok{)}
\CommentTok{#> \{}
\CommentTok{#>   "a": [1],}
\CommentTok{#>   "b": \{}
\CommentTok{#>     "c": ["A", "B"]}
\CommentTok{#>   \},}
\CommentTok{#>   "d": [1, 2, 3, 4, 5]}
\CommentTok{#> \}}
\end{Highlighting}
\end{Shaded}

Looking closely at the list and JSON output above, one quickly sees the resemblance. Something seems odd though: the first value in the list (\texttt{a\ =\ 1}) was serialised\index{serialise} to an array (vector) of length one (\texttt{"a":\ {[}1{]}}), where one would probably expect an integer instead, \texttt{1} not \texttt{{[}1{]}}. This is not a mistake; we often forget that there are no scalar types in R and that \texttt{a} is, in fact, a vector as we can observe below.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{x <-}\StringTok{ }\DecValTok{1}
\KeywordTok{length}\NormalTok{(x)}
\CommentTok{#> [1] 1}
\KeywordTok{is.vector}\NormalTok{(x)}
\CommentTok{#> [1] TRUE}
\end{Highlighting}
\end{Shaded}

JavaScript, on the other hand, does have scalar types; more often than not we will want to convert the vectors of length one to scalar types rather than arrays of length one. To do so we need to use the \texttt{auto\_unbox} argument in \texttt{jsonlite::toJSON}; we'll do this most of the time we have to convert data to JSON\index{JSON}.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{toJSON}\NormalTok{(lst, }\DataTypeTok{pretty =} \OtherTok{TRUE}\NormalTok{, }\DataTypeTok{auto_unbox =} \OtherTok{TRUE}\NormalTok{)}
\CommentTok{#> \{}
\CommentTok{#>   "a": 1,}
\CommentTok{#>   "b": \{}
\CommentTok{#>     "c": ["A", "B"]}
\CommentTok{#>   \},}
\CommentTok{#>   "d": [1, 2, 3, 4, 5]}
\CommentTok{#> \}}
\end{Highlighting}
\end{Shaded}

As demonstrated above the vector of length one was ``unboxed'' into an integer; with \texttt{auto\_unbox} set to \texttt{TRUE}, jsonlite will properly convert such vectors into their appropriate type integer, numeric, boolean, etc. Note that this only applies to vectors lists of length one will be serialised\index{serialise} to arrays of length one even with \texttt{auto\_unbox} turned on: \texttt{list("hello")} will always be converted to \texttt{{[}"hello"{]}}.

\hypertarget{basics-tabular}{%
\subsection{Tabular Data}\label{basics-tabular}}

If JSON is more or less the equivalent of lists in R one might wonder how jsonlite handles dataframes since they do not exist in JavaScript.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# subset of built-in dataset}
\NormalTok{df <-}\StringTok{ }\NormalTok{cars[}\DecValTok{1}\OperatorTok{:}\DecValTok{2}\NormalTok{, ]}

\KeywordTok{toJSON}\NormalTok{(df, }\DataTypeTok{pretty =} \OtherTok{TRUE}\NormalTok{)}
\CommentTok{#> [}
\CommentTok{#>   \{}
\CommentTok{#>     "speed": 4,}
\CommentTok{#>     "dist": 2}
\CommentTok{#>   \},}
\CommentTok{#>   \{}
\CommentTok{#>     "speed": 4,}
\CommentTok{#>     "dist": 10}
\CommentTok{#>   \}}
\CommentTok{#> ]}
\end{Highlighting}
\end{Shaded}

What jsonlite does internally is essentially turn the data.frame into a list \emph{row-wise} to produce a sub-list for every row then it serialises to JSON. This is generally how rectangular data is represented in lists. For instance, \texttt{purrr::transpose} does the same. Another great example is to use \texttt{console.table} in the JavaScript console (more on that later) to display JSON\index{JSON} data as a table (see Figure \ref{fig:console-table}).

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/console-table} 

}

\caption{console.table output}\label{fig:console-table}
\end{figure}

We can reproduce this with the snippet below; we remove row names and use apply to turn every row into a list.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{row.names}\NormalTok{(df) <-}\StringTok{ }\OtherTok{NULL}
\NormalTok{df_list <-}\StringTok{ }\KeywordTok{apply}\NormalTok{(df, }\DecValTok{1}\NormalTok{, as.list)}

\KeywordTok{toJSON}\NormalTok{(df_list, }\DataTypeTok{pretty =} \OtherTok{TRUE}\NormalTok{, }\DataTypeTok{auto_unbox =} \OtherTok{TRUE}\NormalTok{)}
\CommentTok{#> [}
\CommentTok{#>   \{}
\CommentTok{#>     "speed": 4,}
\CommentTok{#>     "dist": 2}
\CommentTok{#>   \},}
\CommentTok{#>   \{}
\CommentTok{#>     "speed": 4,}
\CommentTok{#>     "dist": 10}
\CommentTok{#>   \}}
\CommentTok{#> ]}
\end{Highlighting}
\end{Shaded}

Jsonlite of course also enables reading data from JSON\index{JSON} into R with the function \texttt{fromJSON}.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{json <-}\StringTok{ }\KeywordTok{toJSON}\NormalTok{(df) }\CommentTok{# convert to JSON}
\KeywordTok{fromJSON}\NormalTok{(json) }\CommentTok{# read from JSON}
\CommentTok{#>   speed dist}
\CommentTok{#> 1     4    2}
\CommentTok{#> 2     4   10}
\end{Highlighting}
\end{Shaded}

It's important to note that jsonlite did the conversion back to a data frame. Therefore the code below also returns a data frame even though the object we initially converted to JSON\index{JSON} is a list.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{class}\NormalTok{(df_list)}
\CommentTok{#> [1] "list"}
\NormalTok{json <-}\StringTok{ }\KeywordTok{toJSON}\NormalTok{(df_list)}
\KeywordTok{fromJSON}\NormalTok{(json)}
\CommentTok{#>   speed dist}
\CommentTok{#> 1     4    2}
\CommentTok{#> 2     4   10}
\end{Highlighting}
\end{Shaded}

Jsonlite provides many more options and functions that will let you tune how JSON data is read and written. Also, the jsonlite package does far more than what we detailed in this section. But at this juncture, this is an adequate understanding of things.

\hypertarget{basics-javascript}{%
\section{JavaScript}\label{basics-javascript}}

The book is not meant to teach JavaScript, only to show how graciously it can work with R. Let us thus go through the very basics to ensure we know enough to get started with the coming chapters.

The easiest way to run JavaScript interactively is probably to create an HTML\index{HTML} file (e.g.: \texttt{try.html}), write your code within a \texttt{\textless{}script\textgreater{}} tag and open the file in your web browser\index{web browser}. The console output can be observed in the console of the browser, developer tools (see Figure \ref{fig:trying-js}).

\begin{Shaded}
\begin{Highlighting}[]
\ErrorTok{<}\NormalTok{!–– index.html ––>}
\KeywordTok{<html>}
  \KeywordTok{<head>}
  \KeywordTok{</head>}
  \KeywordTok{<body>}
    \KeywordTok{<p}\OtherTok{ id=}\StringTok{"content"}\KeywordTok{>}\NormalTok{Trying JavaScript!}\KeywordTok{</p>}
  \KeywordTok{</body>}
  \KeywordTok{<script>}
    \CommentTok{// place your JavaScript code here}
    \VariableTok{console}\NormalTok{.}\AttributeTok{log}\NormalTok{(}\StringTok{'Hello JavaScript!'}\NormalTok{)}
  \KeywordTok{</script>}
\KeywordTok{</html>}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/tryingjs} 

}

\caption{Trying JavaScript}\label{fig:trying-js}
\end{figure}

\hypertarget{basics-chrome-devtools}{%
\subsection{Developer Tools}\label{basics-chrome-devtools}}

Most of the JavaScript code written in this book is intended to be run in web browsers\index{web browser}; it is thus vital that you have a great understanding of your web browser\index{web browser} and its developer tools (devtools). In this section, we discuss those available in Google Chrome and Chromium, but such tools, albeit somewhat different, also exist in Mozilla Firefox and Safari.

\begin{rmdnote}
The RStudio IDE\index{RStudio} is built on Chromium, some of these tools
will therefore also work in RStudio.
\end{rmdnote}

The easiest way to access the developer tools from the browser is by ``inspecting'': right-click on an element on a webpage and select ``inspect.'' This will open the developer tools either at the bottom or on the right (Figure \ref{fig:chrome-devtools}) of the page depending on the defaults.

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/devtools} 

}

\caption{Google Chrome devtools}\label{fig:chrome-devtools}
\end{figure}

The developer tools pane consists of several tabs but we will mainly use:

\begin{enumerate}
\def\labelenumi{\arabic{enumi}.}
\tightlist
\item
  Elements: presents the DOM\index{DOM} Tree, the HTML document structure, great for inspecting the structure of the outputs generated from R.
\item
  Console: the JavaScript console where messages, errors, and other such things are logged. Essential for debugging.
\end{enumerate}

\hypertarget{basics-var-scope}{%
\subsection{Variable Declaration and Scope}\label{basics-var-scope}}

One significant way JavaScript differs from R is that variables must be declared using one of three keywords, \texttt{var}, \texttt{let}, or \texttt{const}, which mainly affect the scope\index{scope} where the declared variable will be accessible.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{x }\OperatorTok{=} \DecValTok{1}\OperatorTok{;} \CommentTok{// error}
\KeywordTok{var}\NormalTok{ x }\OperatorTok{=} \DecValTok{1}\OperatorTok{;} \CommentTok{// works}
\end{Highlighting}
\end{Shaded}

One can declare a variable without assigning a value to it, to then do so later on.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{var}\NormalTok{ y}\OperatorTok{;} \CommentTok{// declare }
\NormalTok{y }\OperatorTok{=}\NormalTok{ [}\DecValTok{1}\OperatorTok{,}\DecValTok{2}\OperatorTok{,}\DecValTok{3}\NormalTok{]}\OperatorTok{;} \CommentTok{// define it as array}
\NormalTok{y }\OperatorTok{=} \StringTok{'string'}\OperatorTok{;} \CommentTok{// change to character string}
\end{Highlighting}
\end{Shaded}

The \texttt{let} and \texttt{const} keywords were added in ES2015\index{ECMA}; the \texttt{const} is used to define a constant: a variable that once declared cannot be changed.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{const}\NormalTok{ x }\OperatorTok{=} \DecValTok{1}\OperatorTok{;} \CommentTok{// declare constant}
\NormalTok{x }\OperatorTok{=} \DecValTok{2}\OperatorTok{;} \CommentTok{// error}
\end{Highlighting}
\end{Shaded}

Though this is probably only rarely done in R, one can produce something similar by locking the binding for a variable in its \index{environment}.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{x <-}\StringTok{ }\DecValTok{1} \CommentTok{# declare x}
\KeywordTok{lockBinding}\NormalTok{(}\StringTok{"x"}\NormalTok{, }\DataTypeTok{env =}\NormalTok{ .GlobalEnv) }\CommentTok{# make constant}
\NormalTok{x <-}\StringTok{ }\DecValTok{2} \CommentTok{# error}
\KeywordTok{unlockBinding}\NormalTok{(}\StringTok{"x"}\NormalTok{, }\DataTypeTok{env =}\NormalTok{ .GlobalEnv) }\CommentTok{# unlock binding}
\NormalTok{x <-}\StringTok{ }\DecValTok{2} \CommentTok{# works}
\end{Highlighting}
\end{Shaded}

Notably, \texttt{const} is mainly protecting yourself (the developer) against yourself; if something important is defined and should not change later in the code use \texttt{const} to avoid accidentally reassigning\index{scope} something to it later in the project.

The \texttt{let} keyword is akin to declaring a variable with the \texttt{var} keyword. However, \texttt{let} (and \texttt{const}) will declare the variable in the ``block scope.'' In effect, this further narrows down the scope where the variable will be accessible. A block scope\index{scope} is generally the area within \texttt{if}, \texttt{switch} conditions or \texttt{for} and \texttt{while} loops: areas within curly brackets.

\begin{Shaded}
\begin{Highlighting}[]
\ControlFlowTok{if}\NormalTok{(}\KeywordTok{true}\NormalTok{)}\OperatorTok{\{}
  \KeywordTok{let}\NormalTok{ x }\OperatorTok{=} \DecValTok{1}\OperatorTok{;}
  \KeywordTok{var}\NormalTok{ y }\OperatorTok{=} \DecValTok{1}\OperatorTok{;}
\OperatorTok{\}}

\VariableTok{console}\NormalTok{.}\AttributeTok{log}\NormalTok{(x) }\CommentTok{// error x does not exist}
\VariableTok{console}\NormalTok{.}\AttributeTok{log}\NormalTok{(y) }\CommentTok{// works}
\end{Highlighting}
\end{Shaded}

In the above example, \texttt{x} is only accessible within the if statement as it is declared with \texttt{let}, \texttt{var} does not have block scope.

While on the subject of scope, in R like in JavaScript, variables can be accessed from the parent environment\index{environment} (often referred to as ``context'' in the latter). One immense difference though is that while it is seen as bad practice in R, it is not in JavaScript where it is beneficial.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# it works but don't do this in R}
\NormalTok{x <-}\StringTok{ }\DecValTok{123}
\NormalTok{foo <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{()\{}
  \KeywordTok{print}\NormalTok{(x)}
\NormalTok{\}}
\KeywordTok{foo}\NormalTok{()}
\CommentTok{#> [1] 123}
\end{Highlighting}
\end{Shaded}

The above R code can be re-written in JavaScript. Note the slight variation in the function declaration.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{// this is perfectly fine}
\KeywordTok{var}\NormalTok{ x }\OperatorTok{=} \DecValTok{1}\OperatorTok{;}

\KeywordTok{function} \AttributeTok{foo}\NormalTok{()}\OperatorTok{\{}
  \VariableTok{console}\NormalTok{.}\AttributeTok{log}\NormalTok{(x)}\OperatorTok{;} \CommentTok{// print to console}
\OperatorTok{\}}

\AttributeTok{foo}\NormalTok{()}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

\begin{rmdnote}
Accessing variables from the parent \index{environment} (context) is
useful in JavaScript but should not be done in R
\end{rmdnote}

\hypertarget{basics-object-model}{%
\subsection{Document Object Model}\label{basics-object-model}}

One concept does not exist in R is that of the ``DOM'' which stands for Document Object Model; this is also often referred to as the DOM\index{DOM} tree (represented in Figure \ref{fig:dom-viz}) as it very much follows a tree-like structure.

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/02-dom-viz} 

}

\caption{Document Object Model visualisation}\label{fig:dom-viz}
\end{figure}

When a web page is loaded, the browser creates a Document Object Model of the web page, which can be accessed in JavaScript from the \texttt{document} object. This lets the developer programmatically manipulate the page itself so one can, for instance, add an element (e.g., a button), change the text of another, and plenty more.

The JavaScript code below grabs the element where \texttt{id=\textquotesingle{}content\textquotesingle{}} from the \texttt{document} with \texttt{getElementById} and replaces the text (\texttt{innerText}). Even though the page only contains ``Trying JavaScript!'' when the page is opened (loaded) in the web browser\index{web browser} JavaScript runs the code and changes it: this happens very fast so the original text cannot be seen.

\begin{Shaded}
\begin{Highlighting}[]
 \ErrorTok{<}\NormalTok{!–– index.html ––>}
\KeywordTok{<html>}
  \KeywordTok{<head>}
  \KeywordTok{</head>}
  \KeywordTok{<body>}
    \KeywordTok{<p}\OtherTok{ id=}\StringTok{"content"}\KeywordTok{>}\NormalTok{Trying JavaScript!}\KeywordTok{</p>}
  \KeywordTok{</body>}
  \KeywordTok{<script>}
    \KeywordTok{var}\NormalTok{ cnt }\OperatorTok{=} \VariableTok{document}\NormalTok{.}\AttributeTok{getElementById}\NormalTok{(}\StringTok{"content"}\NormalTok{)}\OperatorTok{;}
    \VariableTok{cnt}\NormalTok{.}\AttributeTok{innerText} \OperatorTok{=} \StringTok{"The text has changed"}\OperatorTok{;}
  \KeywordTok{</script>}
\KeywordTok{</html>}
\end{Highlighting}
\end{Shaded}

One final thing to note for future reference: though not limited to the ids or classes most of such selection of elements from the DOM are done with those where the pound sign refers to an element's id (\texttt{\#id}) and a dot relates to an element's class (\texttt{.class}), just like in CSS.

\begin{Shaded}
\begin{Highlighting}[]
 \ErrorTok{<}\NormalTok{!–– index.html ––>}
\KeywordTok{<html>}
  \KeywordTok{<head>}
  \KeywordTok{</head>}
  \KeywordTok{<body>}
    \KeywordTok{<p}\OtherTok{ id=}\StringTok{"content"}\OtherTok{ class=}\StringTok{"stuff"}\KeywordTok{>}\NormalTok{Trying JavaScript!}\KeywordTok{</p>}
  \KeywordTok{</body>}
  \KeywordTok{<script>}
    \CommentTok{// select by id}
    \KeywordTok{var}\NormalTok{ x }\OperatorTok{=} \VariableTok{document}\NormalTok{.}\AttributeTok{getElementById}\NormalTok{(}\StringTok{"content"}\NormalTok{)}\OperatorTok{;}
    \KeywordTok{var}\NormalTok{ y }\OperatorTok{=} \VariableTok{document}\NormalTok{.}\AttributeTok{querySelector}\NormalTok{(}\StringTok{"#content"}\NormalTok{)}\OperatorTok{;}

    \VariableTok{console}\NormalTok{.}\AttributeTok{log}\NormalTok{(x }\OperatorTok{==}\NormalTok{ y)}\OperatorTok{;} \CommentTok{// true}

    \CommentTok{// select by class}
    \KeywordTok{var}\NormalTok{ z }\OperatorTok{=} \VariableTok{document}\NormalTok{.}\AttributeTok{querySelector}\NormalTok{(}\StringTok{".stuff"}\NormalTok{)}\OperatorTok{;}
  \KeywordTok{</script>}
\KeywordTok{</html>}
\end{Highlighting}
\end{Shaded}

Getting elements from the DOM is a very common operation in JavaScript. A class can be applied to multiple elements, which is useful to select and apply actions to multiple elements. The id attribute must be unique (two elements cannot bear the same id in the HTML document), which is useful to retrieve a specific element.

Interestingly some of that mechanism is used by Shiny to retrieve and manipulate inputs; the argument \texttt{inputId} of Shiny inputs effectively defines the HTML \texttt{id} attribute of said input. Shiny can then internally use functions the likes of \texttt{getElementById} in order to get those inputs, set or update their values, etc.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{shiny}\OperatorTok{::}\KeywordTok{actionButton}\NormalTok{(}\DataTypeTok{inputId =} \StringTok{"theId"}\NormalTok{, }\DataTypeTok{label =} \StringTok{"the label"}\NormalTok{) }
\end{Highlighting}
\end{Shaded}

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{<button} 
\OtherTok{  id=}\StringTok{"theId"} 
\OtherTok{  type=}\StringTok{"button"} 
\OtherTok{  class=}\StringTok{"btn btn-default action-button"}\KeywordTok{>}
\NormalTok{  the label}
\KeywordTok{</button>}
\end{Highlighting}
\end{Shaded}

This, of course, only scratches the surface of JavaScript; thus, this provides ample understanding of the language to keep up with the next chapters. Also, a somewhat interesting fact that will prove useful later in the book: the RStudio IDE is actually a browser, therefore, in the IDE, one can right-click and ``inspect element'' to view the rendered source code.

\hypertarget{basics-shiny}{%
\section{Shiny}\label{basics-shiny}}

It is assumed that the reader has basic knowledge of the Shiny\index{Shiny} framework and already used it to build applications. However, there are some more obscure functionalities that one may not know, but that becomes essential when introducing JavaScript to applications. Chiefly, how to import external dependencies\index{dependency}; JavaScript or otherwise.

There are two ways to import dependencies\index{dependency}: using the htmltools \citep{R-htmltools} package to create a dependency object that Shiny can understand, or manually serving and importing the files with Shiny.

\hypertarget{basics-static-files}{%
\subsection{Serving Static Files}\label{basics-static-files}}

Static files are files that are downloaded by the clients, in this case, web browsers accessing Shiny applications, as-is. These generally include images, CSS (\texttt{.css}), and JavaScript (\texttt{.js}).

If you are familiar with R packages, static files are to Shiny applications what the \texttt{inst} directory is to an R package; those files are installed as-is. They do not require further processing as opposed to the \texttt{src} folder, which contains files that need compiling, for instance.

There are numerous functions to launch a Shiny application locally; the two most used are probably \texttt{shinyApp} and \texttt{runApp}. The RStudio IDE comes with a convenient ``Run'' button when writing a shiny application, which when clicked in fact uses the function \texttt{shiny::runApp} in the background. This function looks for said static files in the \texttt{www} directory and makes them available at the same path (\texttt{/www}). If you are building your applications outside of RStudio\index{RStudio}, you should either also use \texttt{shiny::runApp} or specify the directory which then allows using \texttt{shiny::shinyApp}. Note that this only applies locally; Shiny server (community and pro) as well as \href{https://www.shinyapps.io/}{shinyapps.io} use the same defaults as the RStudio IDE and \texttt{shiny::runApp}.

To ensure the code in this book can run regardless of the reader's machine or editor, the asset\index{asset} directory is always specified explicitly (when used). This is probably advised to steer clear of the potential headaches as, unlike the default, it'll work regardless of the environment\index{environment}. If you are using golem \citep{R-golem} to develop your application, then you should not worry about this as it specifies the directory internally.

Below we build a basic Shiny\index{Shiny} application. However, before we define the \texttt{ui} and \texttt{server}, we use the \texttt{shiny::addResourcePath} function to specify the location of the directory of static files that will be served by the server and thus accessible by the client. This function takes two arguments: first the \texttt{prefix}, which is the path (URL) at which the assets\index{asset} will be available, second the path to the directory of static assets.

We thus create the ``assets''\index{asset} directory and a JavaScript file called \texttt{script.js} within it.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# run from root of app (where app.R is located)}
\KeywordTok{dir.create}\NormalTok{(}\StringTok{"assets"}\NormalTok{)}
\KeywordTok{writeLines}\NormalTok{(}\StringTok{"console.log('Hello JS!');"}\NormalTok{, }\DataTypeTok{con =} \StringTok{"assets/script.js"}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

We can now use the \texttt{shiny::addResourcePath} to point to this directory. Generally, the same name for the directory of static assets\index{asset} and prefix is used to avoid confusion; below we name them differently for the reader to clearly distinguish which is which.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# app.R}
\KeywordTok{library}\NormalTok{(shiny)}

\CommentTok{# serve the files}
\KeywordTok{addResourcePath}\NormalTok{(}
  \CommentTok{# will be accessible at /files}
  \DataTypeTok{prefix =} \StringTok{"files"}\NormalTok{, }
  \CommentTok{# path to the assets directory}
  \DataTypeTok{directoryPath =} \StringTok{"assets"}
\NormalTok{)}

\NormalTok{ui <-}\StringTok{ }\KeywordTok{fluidPage}\NormalTok{(}
  \KeywordTok{h1}\NormalTok{(}\StringTok{"R and JavaScript"}\NormalTok{)}
\NormalTok{)}

\NormalTok{server <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(input, output)\{\}}

\KeywordTok{shinyApp}\NormalTok{(ui, server)}
\end{Highlighting}
\end{Shaded}

If you then run the application and open it at the \texttt{/files/script.js} path (e.g.: \texttt{127.0.0.1:3000/files/script.js}) you should see the content of the JavaScript file (\texttt{console.log(\textquotesingle{}Hello\ JS!\textquotesingle{})}), commenting the \texttt{addResourcePath} line will have a ``Not Found'' error displayed on the page instead.

\begin{rmdnote}
All files in your asset\index{asset} directory will be served online and
accessible to anyone: do not place sensitive files in it.
\end{rmdnote}

Though one may create multiple such directories and correspondingly use \texttt{addResourcePath} to specify multiple paths and prefixes, one will routinely specify a single one, named ``assets''\index{asset} or ``static,'' which contains multiple subdirectories, one for each type of static file to obtain a directory that looks something like the tree below. This is, however, an unwritten convention which is by no means forced upon the developer: do as you wish.

\begin{verbatim}
assets/
├── js/
│    └── script.js
├── css/
│    └── style.css
└── img/
     └── pic.png
\end{verbatim}

At this stage, we have made the JavaScript file we created accessible by the clients, but we still have to source this file in the \texttt{ui} as currently this file is, though served, not used by the application. Were one creating a static HTML\index{HTML} page one would use the \texttt{script} to \texttt{src} the file in the \texttt{head} of the page.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{<html>}
  \KeywordTok{<head>}
    \ErrorTok{<}\NormalTok{!–– source the JavaScript file ––>}
    \KeywordTok{<script}\OtherTok{ src=}\StringTok{"path/to/script.js"}\KeywordTok{></script>}
  \KeywordTok{</head>}
  \KeywordTok{<body>}
    \KeywordTok{<p}\OtherTok{ id=}\StringTok{"content"}\KeywordTok{>}\NormalTok{Trying JavaScript!}\KeywordTok{</p>}
  \KeywordTok{</body>}
\KeywordTok{</html>}
\end{Highlighting}
\end{Shaded}

In Shiny\index{Shiny} we write the UI in R and not in HTML (though this is also supported). Given the resemblance between the names of HTML tags and Shiny UI functions, it is pretty straightforward; the html page above would look something like the Shiny \texttt{ui} below.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(shiny)}

\NormalTok{ui <-}\StringTok{ }\KeywordTok{fluidPage}\NormalTok{(}
  \KeywordTok{singleton}\NormalTok{(}
\NormalTok{    tags}\OperatorTok{$}\KeywordTok{head}\NormalTok{(}
\NormalTok{      tags}\OperatorTok{$}\KeywordTok{script}\NormalTok{(}\DataTypeTok{src =} \StringTok{"path/to/script.js"}\NormalTok{)}
\NormalTok{    )}
\NormalTok{  ),}
  \KeywordTok{p}\NormalTok{(}\DataTypeTok{id =} \StringTok{"content"}\NormalTok{, }\StringTok{"Trying JavaScript!"}\NormalTok{)}
\NormalTok{)}
\end{Highlighting}
\end{Shaded}

The dependency\index{dependency} is used in the \texttt{htmltools::singleton} function ensures that its content is \emph{only imported in the document once.}

Note that we use the \texttt{tags} object, which comes from the Shiny package and includes HTML\index{HTML} tags that are not exported\index{export} as standalone functions. For instance, you can create a \texttt{\textless{}div\textgreater{}} in Shiny with the \texttt{div} function, but \texttt{tags\$div} will also work. This can now be applied to the Shiny application; the \texttt{path/to/script.js} should be changed to \texttt{files/script.js}, where \texttt{files} is the prefix we defined in \texttt{addResourcePath}.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# app.R}
\KeywordTok{library}\NormalTok{(shiny)}

\CommentTok{# serve the files}
\KeywordTok{addResourcePath}\NormalTok{(}\DataTypeTok{prefix =} \StringTok{"files"}\NormalTok{, }\DataTypeTok{directoryPath =} \StringTok{"assets"}\NormalTok{)}

\NormalTok{ui <-}\StringTok{ }\KeywordTok{fluidPage}\NormalTok{(}
\NormalTok{  tags}\OperatorTok{$}\KeywordTok{head}\NormalTok{(}
\NormalTok{    tags}\OperatorTok{$}\KeywordTok{script}\NormalTok{(}\DataTypeTok{src =} \StringTok{"files/script.js"}\NormalTok{)}
\NormalTok{  ),}
  \KeywordTok{h1}\NormalTok{(}\StringTok{"R and JavaScript"}\NormalTok{)}
\NormalTok{)}

\NormalTok{server <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(input, output)\{\}}

\KeywordTok{shinyApp}\NormalTok{(ui, server)}
\end{Highlighting}
\end{Shaded}

From the browser, inspecting page (right click \textgreater{} inspect \textgreater{} console tab) one should see \texttt{Hello\ JS!} in the console, which means the application correctly ran the code in the JavaScript file.

\hypertarget{basics-htmltools}{%
\subsection{Htmltools}\label{basics-htmltools}}

The htmltools package powers much of the Shiny UI, most of the tags that comprise the UI are indeed imported by Shiny from htmltools. For instance \texttt{shiny::actionButton} is just a light wrapper around htmltools \texttt{tags}.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{shiny}\OperatorTok{::}\NormalTok{actionButton}
\end{Highlighting}
\end{Shaded}

\begin{Shaded}
\begin{Highlighting}[]
\ControlFlowTok{function}\NormalTok{ (inputId, label, }\DataTypeTok{icon =} \OtherTok{NULL}\NormalTok{, }\DataTypeTok{width =} \OtherTok{NULL}\NormalTok{, ...) }
\NormalTok{\{}
\NormalTok{    value <-}\StringTok{ }\KeywordTok{restoreInput}\NormalTok{(}\DataTypeTok{id =}\NormalTok{ inputId, }\DataTypeTok{default =} \OtherTok{NULL}\NormalTok{)}
\NormalTok{    tags}\OperatorTok{$}\KeywordTok{button}\NormalTok{(}
      \DataTypeTok{id =}\NormalTok{ inputId, }\DataTypeTok{style =} \ControlFlowTok{if}\NormalTok{ (}\OperatorTok{!}\KeywordTok{is.null}\NormalTok{(width)) }
      \KeywordTok{paste0}\NormalTok{(}\StringTok{"width: "}\NormalTok{, }\KeywordTok{validateCssUnit}\NormalTok{(width), }\StringTok{";"}\NormalTok{),}
      \DataTypeTok{type =} \StringTok{"button"}\NormalTok{, }\DataTypeTok{class =} \StringTok{"btn btn-default action-button"}\NormalTok{, }
      \StringTok{`}\DataTypeTok{data-val}\StringTok{`}\NormalTok{ =}\StringTok{ }\NormalTok{value, }\KeywordTok{list}\NormalTok{(}\KeywordTok{validateIcon}\NormalTok{(icon), label), }
\NormalTok{      ...}
\NormalTok{    )}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

As the name indicates, htmltools goes beyond the generation of HTML tags and provides broader tools to work with HTML from R; this includes working the dependencies. These may appear simple at first: after all, were one working with an HTML document in order to import HTML\index{HTML} or CSS one could use HTML tags.

\begin{Shaded}
\begin{Highlighting}[]
 \ErrorTok{<}\NormalTok{!–– index.html ––>}
\KeywordTok{<html>}
  \KeywordTok{<head>}
    \KeywordTok{<script}\OtherTok{ src=}\StringTok{"path/to/script.js"}\KeywordTok{></script>}
    \KeywordTok{<link}\OtherTok{ rel=}\StringTok{"stylesheet"}\OtherTok{ href=}\StringTok{"path/to/styles.css"}\KeywordTok{>}
  \KeywordTok{</head>}
  \KeywordTok{<body></body>}
\KeywordTok{</html>}
\end{Highlighting}
\end{Shaded}

However, it can quickly get out of hand when working with modules and packages. Imagine having to manage the generation of dependencies, such as the above when multiple functions rely on a dependency\index{dependency}, but being a dependency, it should only be imported once? The unified framework htmltools helps immensely in dealing with these sorts of issues.

The htmltools package provides utilities to import dependencies and ensure these are only rendered once, as they should be. The way this works is by creating a dependency\index{dependency} object that packages like Shiny and R markdown\index{R markdown} can understand and translate into HTML dependencies. This is handled with the \texttt{htmlDependency} function, which returns an object of class \texttt{html\_dependency}.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{dependency <-}\StringTok{ }\NormalTok{htmltools}\OperatorTok{::}\KeywordTok{htmlDependency}\NormalTok{(}
  \DataTypeTok{name =} \StringTok{"myDependency"}\NormalTok{,}
  \DataTypeTok{version =} \StringTok{"1.0.0"}\NormalTok{,}
  \DataTypeTok{src =} \KeywordTok{c}\NormalTok{(}\DataTypeTok{file =} \StringTok{"path/to/directory"}\NormalTok{),}
  \DataTypeTok{script =} \StringTok{"script.js"}\NormalTok{,}
  \DataTypeTok{stylesheet =} \StringTok{"styles.css"}
\NormalTok{)}
\end{Highlighting}
\end{Shaded}

About the above, the \texttt{src} argument points to the directory that contains the dependencies\index{dependency} (\texttt{script} and \texttt{stylesheet}); this is done with a named vector where \texttt{file} indicates the path is a local directory and \texttt{href} indicates it is a remote server, generally a CDN\index{CDN}. Note that one can also pass multiple \texttt{script} and \texttt{stylesheet} by using vectors, e.g.: \texttt{c("script.js",\ "anotherScript.js")}

\begin{rmdnote}
CDN stands for Content Delivery Network, a geographically distributed
group of servers that provide fast transfer of
dependencies\index{dependency}.
\end{rmdnote}

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# dependency to the latest jQuery}
\NormalTok{dependency <-}\StringTok{ }\NormalTok{htmltools}\OperatorTok{::}\KeywordTok{htmlDependency}\NormalTok{(}
  \DataTypeTok{name =} \StringTok{"myDependency"}\NormalTok{,}
  \DataTypeTok{version =} \StringTok{"1.0.0"}\NormalTok{,}
  \DataTypeTok{src =} \KeywordTok{c}\NormalTok{(}
    \DataTypeTok{href =} \StringTok{"https://cdn.jsdelivr.net/gh/jquery/jquery/dist/"}
\NormalTok{  ),}
  \DataTypeTok{script =} \StringTok{"jquery.min.js"}
\NormalTok{)}
\end{Highlighting}
\end{Shaded}

Shiny, R markdown, and other packages where htmltools is relevant will then be able to translate an \texttt{html\_dependency} object into actual HTML dependencies. The above would, for instance, generate the following HTML.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{<script} 
\OtherTok{  src=}\StringTok{"https://cdn.jsdelivr.net/gh/jquery/jquery/}
\StringTok{    dist/jquery.min.js"}\KeywordTok{>}
\KeywordTok{</script>}
\end{Highlighting}
\end{Shaded}

Notably, the \texttt{htmltools::htmlDependency} also takes a \texttt{package} argument, which makes it such that the \texttt{src} path becomes relative to the package directory (the \texttt{inst} folder). Hence the snippet below imports a file located at \texttt{myPackage/inst/assets/script.js}; the ultimate full path will, of course, depend on where the package is installed on the users' machine.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{dependency <-}\StringTok{ }\NormalTok{htmltools}\OperatorTok{::}\KeywordTok{htmlDependency}\NormalTok{(}
  \DataTypeTok{name =} \StringTok{"myDependency"}\NormalTok{,}
  \DataTypeTok{version =} \StringTok{"1.0.0"}\NormalTok{,}
  \DataTypeTok{src =} \StringTok{"assets"}\NormalTok{,}
  \DataTypeTok{script =} \KeywordTok{c}\NormalTok{(}\DataTypeTok{file =} \StringTok{"script.js"}\NormalTok{),}
  \DataTypeTok{package =} \StringTok{"myPackage"} \CommentTok{# user package}
\NormalTok{)}
\end{Highlighting}
\end{Shaded}

However, how does one use it in R markdown\index{R markdown} or Shiny? Well, merely placing it in the Shiny UI or an evaluated R markdown\index{R markdown} chunk will do the job.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# place it in the shiny UI}
\NormalTok{ui <-}\StringTok{ }\KeywordTok{fluidPage}\NormalTok{(}
\NormalTok{  htmltools}\OperatorTok{::}\KeywordTok{htmlDependency}\NormalTok{(}
    \DataTypeTok{name =} \StringTok{"myDependency"}\NormalTok{,}
    \DataTypeTok{version =} \StringTok{"1.0.0"}\NormalTok{,}
    \DataTypeTok{src =} \StringTok{"assets"}\NormalTok{,}
    \DataTypeTok{script =} \KeywordTok{c}\NormalTok{(}\DataTypeTok{file =} \StringTok{"script.js"}\NormalTok{),}
    \DataTypeTok{package =} \StringTok{"myPackage"} \CommentTok{# user package}
\NormalTok{  )}
\NormalTok{)}
\end{Highlighting}
\end{Shaded}

\hypertarget{basics-deps-pro-cons}{%
\subsection{Serving vs.~htmltools}\label{basics-deps-pro-cons}}

For multiple reasons, the best way to include dependencies\index{dependency} is probably the former using htmltools. First, it will work with both Shiny and rmarkdown \citep{R-rmarkdown} (whereas the other method previously described only works with Shiny), reducing the cognitive load on the developer (you). Learn to use this method and you will be able to import dependencies\index{dependency} for many different output types. Moreover, it comes with neat features that will be explored later in the book, e.g., dynamic dependencies for interactive visualisations or Shiny.

Also, using htmltools dependencies will allow other package developers to assess and access the dependencies you build quickly. The function \texttt{findDependencies} will accept another function from which it can extract the dependencies\index{dependency}. The object it returns can then be used elsewhere, making dependencies portable. Below we use this function to extract the dependencies of the \texttt{fluidPage} function from the Shiny package.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{htmltools}\OperatorTok{::}\KeywordTok{findDependencies}\NormalTok{(}
\NormalTok{  shiny}\OperatorTok{::}\KeywordTok{fluidPage}\NormalTok{()}
\NormalTok{) }
\end{Highlighting}
\end{Shaded}

\begin{verbatim}
#> [[1]]
#> List of 10
#>  $ name      : chr "bootstrap"
#>  $ version   : chr "3.4.1"
#>  $ src       :List of 2
#>   ..$ href: chr "shared/bootstrap"
#>   ..$ file: chr "/Library/shiny/www/shared/bootstrap"
#>  $ meta      :List of 1
#>   ..$ viewport: chr "width=device-width, initial-scale=1"
#>  $ script    : chr [1:3] "js/bootstrap.min.js" 
  "shim/html5shiv.min.js" 
  "shim/respond.min.js"
#>  $ stylesheet: chr "css/bootstrap.min.css"
#>  $ head      : NULL
#>  $ attachment: NULL
#>  $ package   : NULL
#>  $ all_files : logi TRUE
#>  - attr(*, "class")= chr "html_dependency"
\end{verbatim}

Extracting dependencies\index{dependency} from other packages will become useful later in the book as we assess compatibility between packages: making sure dependencies do not clash and importing dependencies\index{dependency} from other packages.

Using \texttt{shiny::addResourcePath} has one advantage: its use is not limited to making CSS and JavaScript files available in Shiny; it can be used to serve other file types such as JSON or images that may also be needed in the application.

\hypertarget{part-data-visualisation}{%
\part{Data Visualisation}\label{part-data-visualisation}}

\hypertarget{widgets-intro-intro}{%
\chapter{Introduction to Widgets}\label{widgets-intro-intro}}

This part of the book explores the integration of JavaScript with R using the htmlwidgets\index{htmlwidgets} package, which focuses on libraries that produce a visual output. It is often used for data visualisation but is not limited to it.

As in future parts of this book, we mainly learn through examples, building multiple widgets of increasing complexity as we progress through the chapters. Before writing the first widget, we explore existing R packages that allow creating interactive data visualisations as this gives a first glimpse at what we ultimately build in this part of the book. Then we explore JavaScript libraries that make great candidates for htmlwidgets and attempt to understand how they work to grasp what is expected from the developer in order to integrate them with R. Finally, we build upon the previous chapter to improve how htmlwidgets work with Shiny\index{Shiny}.

The htmlwidgets\index{htmlwidgets} package originates from the rCharts \citep{R-rCharts} package created in 2012 by Ramnath Vaidyanathan. It brought together a plethora of data visualisation\index{visualisation} JavaScript libraries, datamaps, highcharts, morris.js, and many more. Though no longer maintained rCharts ultimately paved the way towards a framework for interactive visualisations in R: two years later, in 2014, Ramnath and other prominent R users start working on htmlwidgets.

The objective of this chapter is to explore existing widgets available on CRAN\index{CRAN}, discover how they work, whilst focusing on their prominent features as we learn how to implement those in our very own widget in the coming chapters.

\hypertarget{widgets-plotly}{%
\section{Plotly package}\label{widgets-plotly}}

The plotly \citep{R-plotly} R package is probably one of the first and the most popular widget built thus far; it has been downloaded from CRAN\index{CRAN} 4.9 million times at the time of writing this.

Plotly.js is a substantial library that provides over 40 chart types, including 3D charts, statistical graphs, and maps, all of which are available from the R interface. There is so much depth to plotly that there is an entire \href{https://plotly-r.com/}{book} on the topic: \emph{Interactive web-based data visualization with R, plotly, and shiny.}

The very short snippet of code below creates Figure \ref{fig:plotly-scatter-diagram}, an interactive scatter plot.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(plotly)}

\KeywordTok{plot_ly}\NormalTok{(cars, }\DataTypeTok{x =} \OperatorTok{~}\NormalTok{speed, }\DataTypeTok{y =} \OperatorTok{~}\NormalTok{dist) }\OperatorTok{%>%}\StringTok{ }
\StringTok{  }\KeywordTok{add_markers}\NormalTok{()}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/03-plotly-scatter} 

}

\caption{plotly scatter plot}\label{fig:plotly-scatter-diagram}
\end{figure}

Plotly also has the ability to translate static ggplot2 \citep{R-ggplot2} charts to interactive plotly charts with the \texttt{ggplotly} function, as demonstrated in Figure \ref{fig:plotly-ggplotly-diagram}.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{p <-}\StringTok{ }\KeywordTok{ggplot}\NormalTok{(diamonds, }\KeywordTok{aes}\NormalTok{(}\DataTypeTok{x =} \KeywordTok{log}\NormalTok{(carat), }\DataTypeTok{y =} \KeywordTok{log}\NormalTok{(price))) }\OperatorTok{+}\StringTok{ }
\StringTok{  }\KeywordTok{geom_hex}\NormalTok{(}\DataTypeTok{bins =} \DecValTok{100}\NormalTok{)}
\KeywordTok{ggplotly}\NormalTok{(p)}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/03-ggplotly} 

}

\caption{Interactive ggplot2 with plotly}\label{fig:plotly-ggplotly-diagram}
\end{figure}

All plotly charts are initialised with the \texttt{plot\_ly} function and work nicely with the magrittr \citep{R-magrittr} pipe\index{pipe} \texttt{\%\textgreater{}\%}. This implies that (almost) every function expects a plotly object (the output of \texttt{plot\_ly}) and returns a modified version of that object. The pipe\index{pipe} makes code easier to read and more concise.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{p <-}\StringTok{ }\KeywordTok{plot_ly}\NormalTok{(cars, }\DataTypeTok{x =} \OperatorTok{~}\NormalTok{speed, }\DataTypeTok{y =} \OperatorTok{~}\NormalTok{dist) }
\NormalTok{p <-}\StringTok{ }\KeywordTok{add_markers}\NormalTok{(p)}
\end{Highlighting}
\end{Shaded}

Plotly implements geoms in a similar fashion as ggplot2, functions that start in \texttt{add\_} add a layer to the plot (e.g.: \texttt{add\_lines}, \texttt{add\_bars}), making it easy to combine series into a single chart, as in Figure \ref{fig:plotly-layers-diagram}.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{plot_ly}\NormalTok{(mtcars, }\DataTypeTok{x =} \OperatorTok{~}\NormalTok{disp) }\OperatorTok{%>%}\StringTok{ }
\StringTok{  }\KeywordTok{add_markers}\NormalTok{(}\DataTypeTok{y =} \OperatorTok{~}\NormalTok{mpg, }\DataTypeTok{text =} \KeywordTok{rownames}\NormalTok{(mtcars)) }\OperatorTok{%>%}\StringTok{ }
\StringTok{  }\KeywordTok{add_lines}\NormalTok{(}\DataTypeTok{y =} \OperatorTok{~}\KeywordTok{fitted}\NormalTok{(}\KeywordTok{loess}\NormalTok{(mpg }\OperatorTok{~}\StringTok{ }\NormalTok{disp)))}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/03-plotly-multiple} 

}

\caption{Multiple layers with plotly}\label{fig:plotly-layers-diagram}
\end{figure}

\hypertarget{widgets-intro-dt}{%
\section{DT package}\label{widgets-intro-dt}}

The DT package \citep{R-DT} is a wrapper for the \href{https://datatables.net/}{DataTables} jQuery plug-in, which allows creating interactive tables from R \texttt{data.frame} objects, it's as simple as a single line of code (see Figure \ref{fig:plotly-dt-diagram}).

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{DT}\OperatorTok{::}\KeywordTok{datatable}\NormalTok{(cars)}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/03-DT} 

}

\caption{Interactive table with DT}\label{fig:plotly-dt-diagram}
\end{figure}

DT has grown very popular amongst Shiny developers as it allows capturing server-side many of the users' interactions with the table, such as the selected row, as demonstrated in Figure \ref{fig:dt-example}.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(DT)}
\KeywordTok{library}\NormalTok{(shiny)}

\NormalTok{ui <-}\StringTok{ }\KeywordTok{fluidPage}\NormalTok{(}
  \KeywordTok{fluidRow}\NormalTok{(}
    \KeywordTok{column}\NormalTok{(}\DecValTok{8}\NormalTok{, }\KeywordTok{DTOutput}\NormalTok{(}\StringTok{"myTable"}\NormalTok{)),}
    \KeywordTok{column}\NormalTok{(}
      \DecValTok{4}\NormalTok{,}
      \KeywordTok{h4}\NormalTok{(}\StringTok{"Indices of selected rows"}\NormalTok{), }
      \KeywordTok{verbatimTextOutput}\NormalTok{(}\StringTok{"selected"}\NormalTok{)}
\NormalTok{    )}
\NormalTok{  )}
\NormalTok{)}

\NormalTok{server <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(input, output) \{}

\NormalTok{  output}\OperatorTok{$}\NormalTok{myTable <-}\StringTok{ }\KeywordTok{renderDT}\NormalTok{(\{}
    \KeywordTok{datatable}\NormalTok{(mtcars)}
\NormalTok{  \})}

\NormalTok{  output}\OperatorTok{$}\NormalTok{selected <-}\StringTok{ }\KeywordTok{renderPrint}\NormalTok{(\{}
\NormalTok{    input}\OperatorTok{$}\NormalTok{myTable_rows_selected}
\NormalTok{  \})}

\NormalTok{\}}

\KeywordTok{shinyApp}\NormalTok{(ui, server)}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/DT-example} 

}

\caption{DT package example}\label{fig:dt-example}
\end{figure}

\hypertarget{widgets-intro-crosstalk}{%
\section{Crosstalk}\label{widgets-intro-crosstalk}}

DT and plotly both fully support the crosstalk package \citep{R-crosstalk}, a package to enable two widgets to communicate. In the Figure \ref{fig:dt-example-crosstalk}, we use crosstalk to create a ``shared dataset'' that can be used to create 1) a table with DT, and 2) a scatter plot with plotly. Rows selected in the table are highlighted in the plot and vice versa.

The \texttt{bscols} function is just a convenience function that makes it easy to put the visualisation and table side-by-side.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(DT)}
\KeywordTok{library}\NormalTok{(plotly)}
\KeywordTok{library}\NormalTok{(crosstalk)}

\NormalTok{sd <-}\StringTok{ }\NormalTok{SharedData}\OperatorTok{$}\KeywordTok{new}\NormalTok{(iris[, }\KeywordTok{c}\NormalTok{(}\StringTok{"Sepal.Length"}\NormalTok{, }\StringTok{"Sepal.Width"}\NormalTok{)])}

\KeywordTok{bscols}\NormalTok{(}
  \DataTypeTok{device =} \StringTok{"lg"}\NormalTok{,}
  \KeywordTok{datatable}\NormalTok{(sd, }\DataTypeTok{width =} \StringTok{"100%"}\NormalTok{),}
  \KeywordTok{plot_ly}\NormalTok{(sd, }\DataTypeTok{x =} \OperatorTok{~}\NormalTok{Sepal.Length, }\DataTypeTok{y =} \OperatorTok{~}\NormalTok{Sepal.Width)}
\NormalTok{)}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/dt-crosstalk-intro} 

}

\caption{DT and plotly with crosstalk}\label{fig:dt-example-crosstalk}
\end{figure}

\hypertarget{widgets-intro-conclude}{%
\section{Wrap-up}\label{widgets-intro-conclude}}

These are only two examples of widgets and how they can work together. But we hope this makes a compelling case for building such software as we next learn how to build them, integrate them with crosstalk, Shiny\index{Shiny}, and much more.

\hypertarget{widgets-basics}{%
\chapter{Basics of Building Widgets}\label{widgets-basics}}

Having explored existing packages that build on top of the htmlwidgets\index{htmlwidgets} package gives some idea of the end product, but much of how it works and where to start probably remains somewhat mysterious.

\hypertarget{widgets-basics-study}{%
\section{Read and Study}\label{widgets-basics-study}}

Once you have found an impressive library that you would like to use from R, the very first step when building a widget is to study the JavaScript library you want to integrate thoroughly.

\begin{enumerate}
\def\labelenumi{\arabic{enumi}.}
\tightlist
\item
  Start where the documentation tells you to start, often a ``hello world'' example, or a get-started section. This will already give you a good sense of how this library functions, the expected data format, and more.
\item
  Second, it's good to head to the ``installation'' part of the documentation to know more about the library's dependencies\index{dependency}, see whether it is modularised or available in a single bundle, etc.
\item
  Look at examples in great depth. One cue to know if the library will be more or less complex to integrate with R is whether the various snippets of code that generate the examples are similar or drastically different: commonalities make for easier abstractions and ultimately simpler R code and packages. Some libraries will ultimately be more straightforward to integrate than others.
\item
  At this stage you should have some idea of what it will take to bring the library to R, and though you likely are vaguely familiar with the functions and methods that comprise the library you must look at the ``API,'' or proper ``documentation'' of the API to grasp precisely what is available.
\item
  Finally, before starting the R work, it is advised to properly experience using the library as it was intended: with JavaScript and HTML. This will further give a sense of which parts of the API are great and which not so much. This is useful to know because you will get to improve or mirror this API in R when you develop the widget for it.
\end{enumerate}

This is likely a section you will want to come back to at the end of this part as you browse for libraries to integrate into your workflow.

\hypertarget{widgets-basics-candidates}{%
\section{Candidate Libraries}\label{widgets-basics-candidates}}

Before going down the rabbit hole, let us explore the types of libraries you will work with; htmlwidgets' main clients so to speak. Below we look at some such popular libraries and briefly analyse how they work and what they have in common. This will significantly help readers conceptualise what trying to achieve in this chapter.

\hypertarget{widgets-basics-candidates-plotly}{%
\subsection{Plotly.js}\label{widgets-basics-candidates-plotly}}

\href{https://plotly.com/javascript/}{Plotly.js} is probably one of the more popular out there; it provides over 40 fully customisable chart types, many of which are very sophisticated. That is indeed the JavaScript library used by the R package of the same name: plotly.

Looking at the code presented in the ``Get Started'' guide reveals just how convenient the library is. In Figure \ref{fig:candidate-plotly} we import plotly, of course, then have a \texttt{\textless{}div\textgreater{}} where the visualisation will be placed. Then, using \texttt{Plotly.newPlot}, create the actual visualisation by passing it first the element previously mentioned and a JSON\index{JSON} of options that describe the chart.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{<html}\OtherTok{ xmlns=}\StringTok{"http://www.w3.org/1999/xhtml"}\OtherTok{ lang=}\StringTok{""}\OtherTok{ xml:lang=}\StringTok{""}\KeywordTok{>}
\KeywordTok{<head>}
  \CommentTok{<!-- Import library -->}
  \KeywordTok{<script}\OtherTok{ src=}\StringTok{"plotly-latest.min.js"}\KeywordTok{></script>}
\KeywordTok{</head>}
\KeywordTok{<body>}
  \CommentTok{<!-- div to hold visualisation -->}
  \KeywordTok{<div}\OtherTok{ id=}\StringTok{"chart"}\OtherTok{ style=}\StringTok{"width:600px;height:400px;"}\KeywordTok{></div>}
  \CommentTok{<!-- Script to create visualisation -->}
  \KeywordTok{<script>}
\NormalTok{    el }\OperatorTok{=} \VariableTok{document}\NormalTok{.}\AttributeTok{getElementById}\NormalTok{(}\StringTok{'chart'}\NormalTok{)}\OperatorTok{;}
    \VariableTok{Plotly}\NormalTok{.}\AttributeTok{newPlot}\NormalTok{(el}\OperatorTok{,}\NormalTok{ [}\OperatorTok{\{}
      \DataTypeTok{x}\OperatorTok{:}\NormalTok{ [}\DecValTok{1}\OperatorTok{,} \DecValTok{2}\OperatorTok{,} \DecValTok{3}\OperatorTok{,} \DecValTok{4}\OperatorTok{,} \DecValTok{5}\NormalTok{]}\OperatorTok{,}
      \DataTypeTok{y}\OperatorTok{:}\NormalTok{ [}\DecValTok{1}\OperatorTok{,} \DecValTok{2}\OperatorTok{,} \DecValTok{4}\OperatorTok{,} \DecValTok{8}\OperatorTok{,} \DecValTok{16}\NormalTok{] }\OperatorTok{\}}\NormalTok{]}
\NormalTok{    )}\OperatorTok{;}
  \KeywordTok{</script>}
\KeywordTok{</body>}
\KeywordTok{</html>}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/candidate-plotly} 

}

\caption{Plotly example}\label{fig:candidate-plotly}
\end{figure}

Now let's look at how another popular library does it.

\hypertarget{widgets-basics-candidates-highcharts}{%
\subsection{Highchart.js}\label{widgets-basics-candidates-highcharts}}

\href{https://www.highcharts.com/}{Highcharts} is another library that allows creating gorgeous visualisation\index{visualisation}, maps, and more; it's also very popular, albeit not being entirely free.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{<html}\OtherTok{ xmlns=}\StringTok{"http://www.w3.org/1999/xhtml"}\OtherTok{ lang=}\StringTok{""}\OtherTok{ xml:lang=}\StringTok{""}\KeywordTok{>}
\KeywordTok{<head>}
  \CommentTok{<!-- Import library -->}
  \KeywordTok{<script}\OtherTok{ src=}\StringTok{"highcharts.js"}\KeywordTok{></script>}
\KeywordTok{</head>}
\KeywordTok{<body>}
  \CommentTok{<!-- div to hold visualisation -->}
  \KeywordTok{<div}\OtherTok{ id=}\StringTok{"chart"}\OtherTok{ style=}\StringTok{"width:100%;height:400px;"}\KeywordTok{></div>}
  \CommentTok{<!-- Script to create visualisation -->}
  \KeywordTok{<script>}
    \KeywordTok{var}\NormalTok{ myChart }\OperatorTok{=} \VariableTok{Highcharts}\NormalTok{.}\AttributeTok{chart}\NormalTok{(}\StringTok{'chart'}\OperatorTok{,} \OperatorTok{\{}
        \DataTypeTok{xAxis}\OperatorTok{:} \OperatorTok{\{}
            \DataTypeTok{categories}\OperatorTok{:}\NormalTok{ [}\StringTok{'Apples'}\OperatorTok{,} \StringTok{'Bananas'}\OperatorTok{,} \StringTok{'Oranges'}\NormalTok{]}
        \OperatorTok{\},}
        \DataTypeTok{series}\OperatorTok{:}\NormalTok{ [}\OperatorTok{\{}
            \DataTypeTok{name}\OperatorTok{:} \StringTok{'Jane'}\OperatorTok{,}
            \DataTypeTok{data}\OperatorTok{:}\NormalTok{ [}\DecValTok{1}\OperatorTok{,} \DecValTok{0}\OperatorTok{,} \DecValTok{4}\NormalTok{]}
        \OperatorTok{\},} \OperatorTok{\{}
            \DataTypeTok{name}\OperatorTok{:} \StringTok{'John'}\OperatorTok{,}
            \DataTypeTok{data}\OperatorTok{:}\NormalTok{ [}\DecValTok{5}\OperatorTok{,} \DecValTok{7}\OperatorTok{,} \DecValTok{3}\NormalTok{]}
        \OperatorTok{\}}\NormalTok{]}
    \OperatorTok{\}}\NormalTok{)}\OperatorTok{;}
  \KeywordTok{</script>}
\KeywordTok{</body>}
\KeywordTok{</html>}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/candidate-highcharts} 

}

\caption{Highcharts example}\label{fig:candidate-highcharts}
\end{figure}

Figure \ref{fig:candidate-highcharts} is very similar to what plotly.js requires: import libraries, create a \texttt{\textless{}div\textgreater{}} where to put the visualisation\index{visualisation}. Then, to create the chart, run a function which also takes the id of the div where to place said chart and a JSON of options defining the actual chart, including the data.

\hypertarget{widgets-basics-candidates-chart.js}{%
\subsection{Chart.js}\label{widgets-basics-candidates-chart.js}}

\href{https://www.chartjs.org/}{Chart.js} is yet another library with which to draw standard charts; it is popular for its permissive license and convenient API.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{<html}\OtherTok{ xmlns=}\StringTok{"http://www.w3.org/1999/xhtml"}\OtherTok{ lang=}\StringTok{""}\OtherTok{ xml:lang=}\StringTok{""}\KeywordTok{>}
\KeywordTok{<head>}
  \CommentTok{<!-- Import library -->}
  \KeywordTok{<script}\OtherTok{ src=}\StringTok{"Chart.min.js"}\KeywordTok{></script>}
\KeywordTok{</head>}
\KeywordTok{<body>}
  \CommentTok{<!-- canvas to hold visualisation -->}
  \KeywordTok{<canvas}\OtherTok{ id=}\StringTok{"chart"}\KeywordTok{></canvas>}
  \CommentTok{<!-- Script to create visualisation -->}
  \KeywordTok{<script>}
    \KeywordTok{var}\NormalTok{ el }\OperatorTok{=} \VariableTok{document}\NormalTok{.}\AttributeTok{getElementById}\NormalTok{(}\StringTok{'chart'}\NormalTok{).}\AttributeTok{getContext}\NormalTok{(}\StringTok{'2d'}\NormalTok{)}\OperatorTok{;}    
    \KeywordTok{var}\NormalTok{ myChart }\OperatorTok{=} \KeywordTok{new} \AttributeTok{Chart}\NormalTok{(el}\OperatorTok{,} \OperatorTok{\{}
      \DataTypeTok{type}\OperatorTok{:} \StringTok{'bar'}\OperatorTok{,}
      \DataTypeTok{data}\OperatorTok{:} \OperatorTok{\{}
        \DataTypeTok{labels}\OperatorTok{:}\NormalTok{ [}
          \StringTok{'Red'}\OperatorTok{,} \StringTok{'Blue'}\OperatorTok{,} \StringTok{'Yellow'}\OperatorTok{,} \StringTok{'Green'}\OperatorTok{,} 
          \StringTok{'Purple'}\OperatorTok{,} \StringTok{'Orange'}\NormalTok{]}\OperatorTok{,}
        \DataTypeTok{datasets}\OperatorTok{:}\NormalTok{ [}\OperatorTok{\{}
          \DataTypeTok{label}\OperatorTok{:} \StringTok{'# of Votes'}\OperatorTok{,}
          \DataTypeTok{data}\OperatorTok{:}\NormalTok{ [}\DecValTok{12}\OperatorTok{,} \DecValTok{19}\OperatorTok{,} \DecValTok{3}\OperatorTok{,} \DecValTok{5}\OperatorTok{,} \DecValTok{2}\OperatorTok{,} \DecValTok{3}\NormalTok{]}
        \OperatorTok{\}}\NormalTok{]}
      \OperatorTok{\}}
    \OperatorTok{\}}\NormalTok{)}\OperatorTok{;}
  \KeywordTok{</script>}
\KeywordTok{</body>}
\KeywordTok{</html>}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/candidate-chartjs} 

}

\caption{Chart.js example}\label{fig:candidate-chartjs}
\end{figure}

In Figure \ref{fig:candidate-chartjs}, we again observe a very similar structure as with previous libraries. The library is imported; instead of a \texttt{div} chart.js uses a \texttt{canvas}, the visualisation\index{visualisation} is also created from a single function which takes the canvas as first argument and a JSON of options as second.

Hopefully, this reveals the repeating structure such libraries tend to follow as well as demonstrate how little JavaScript code is involved. It also hints at what should be reproduced, to some extent at least, using R.

\hypertarget{widgets-basics-inner-workings}{%
\section{How It Works}\label{widgets-basics-inner-workings}}

Imagine there is no such package as htmlwidgets\index{htmlwidgets} to help create interactive visualisations from R: how would one attempt to go about it?

As observed, an interactive visualisation using JavaScript will be contained within an HTML\index{HTML} document. Therefore it would probably have to be created first. Secondly, the visualisation that is yet to be created likely relies on external libraries; these would need to be imported in the document. The document should also include an HTML\index{HTML} element (e.g.: \texttt{\textless{}div\textgreater{}}) to host said visualisation\index{visualisation}. Then data would have to be serialised\index{serialise} in R and embedded into the document, where it should be read by JavaScript code that uses it to create the visualisation. Finally, all should be managed to work seamlessly across R markdown\index{R markdown}, Shiny\index{Shiny}, and other environments.

This gives the basic diagram shown in Figure \ref{fig:widget-inner-diagram}; it will be broken down further in the next chapter as the first widget is built.

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/03-htmlwidget-viz} 

}

\caption{htmlwidgets inner-workings visualised}\label{fig:widget-inner-diagram}
\end{figure}

Thankfully the htmlwidgets package is there to handle most of this. Nonetheless, it is essential to understand that these operations are undertaken (to some degree) by htmlwidgets.

\hypertarget{widgets-first}{%
\chapter{Your First Widget}\label{widgets-first}}

The previous chapter gave some indication as to how widgets work, but this is overall probably still shrouded in mystery. This chapter aims at demystifying what remains confusing. That is done by building a very basic widget to rummage through its components to observe how they interact and ultimately grasp a greater understanding of how such interactive outputs are actually produced.

\hypertarget{widgets-first-scaffold}{%
\section{The Scaffold}\label{widgets-first-scaffold}}

Though one could probably create widgets outside of an R package, it would only make things more complicated. Htmlwidgets\index{htmlwidgets} naturally take the form of R packages and are stunningly simple to create. Below we create a package named ``playground,'' which will be used to mess around and explore.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{usethis}\OperatorTok{::}\KeywordTok{create_package}\NormalTok{(}\StringTok{"playground"}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

Then, from the root of the package created, we scaffold\index{scaffold} a widget which we call ``play.''

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{htmlwidgets}\OperatorTok{::}\KeywordTok{scaffoldWidget}\NormalTok{(}\StringTok{"play"}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

This function puts together the minimalistic structure necessary to implement an htmlwidget and opens \texttt{play.R}, \texttt{play.js}, and \texttt{play.yaml} in the RStudio IDE or the default text editor.

\begin{rmdnote}
You can scaffold multiple widgets in a single package.
\end{rmdnote}

These files are named after the widget and will form the core of the package. The R file contains core functions of the R API, namely the \texttt{play} function, which creates the widget itself, and the \texttt{render*} and \texttt{*output} functions that handle the widget in the Shiny\index{Shiny} server and UI, respectively. The \texttt{.js} file contains JavaScript functions that generate the visual output.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{devtools}\OperatorTok{::}\KeywordTok{document}\NormalTok{()}
\NormalTok{devtools}\OperatorTok{::}\KeywordTok{load_all}\NormalTok{()}
\end{Highlighting}
\end{Shaded}

It might be hard to believe, but at this stage one already has a fully functioning widget ready to use after documenting, and building the package. Indeed, the \texttt{play.R} file that was created contains a function named ``play,'' which takes, amongst other arguments, a message.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{play}\NormalTok{(}\DataTypeTok{message =} \StringTok{"This is a widget!"}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/playground-1} 

}

\caption{First widget}\label{fig:playground-1}
\end{figure}

Figure \ref{fig:playground-1} displays the message in the RStudio\index{RStudio} ``Viewer,'' or your default browser; indicating the function does indeed create an HTML\index{HTML} output. One can use the \includegraphics{images/open-in-browser.png} button located in the top right of the RStudio\index{RStudio} ``Viewer'' to open the message in the web browser\index{web browser}, which can prove very useful to look under the hood of the widgets for debugging.

\hypertarget{widgets-first-htmloutput}{%
\section{The HTML Output}\label{widgets-first-htmloutput}}

With an out-of-the-box htmlwidgets package, one can start exploring the internals to understand how it works. Let us start by retracing the path taken by the message written in R to its seemingly magical appearance in HTML\index{HTML}. The \texttt{play} function previously used, takes the \texttt{message} wraps it into a list which is then used in \texttt{htmlwidgets::createWidget}.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# forward options using x}
\NormalTok{x =}\StringTok{ }\KeywordTok{list}\NormalTok{(}
  \DataTypeTok{message =}\NormalTok{ message}
\NormalTok{)}
\end{Highlighting}
\end{Shaded}

Wrapping a string in a list might seem unnecessary, but one will eventually add variables when building a more complex widget, starting with a list makes it easier to add them later on.

To investigate the widget we should look under the hood; the source code of the created (and rendered) output can be accessed in different ways, 1) by right-clicking on the message displayed in the RStudio\index{RStudio} Viewer and selecting ``Inspect element,'' or 2) by opening the visualisation in your browser using the \includegraphics{images/open-in-browser.png} button located in the top right of the ``Viewer,'' and in the browser right-click on the message to select ``Inspect.'' The latter is advised as web browsers\index{web browser} such as Chrome or Firefox provide much friendlier interfaces for such functionalities. They also come with shortcuts to inspect or view the source code of a page.

Below is a part of the \texttt{\textless{}body\textgreater{}} of the output of \texttt{play("This\ is\ a\ widget!")} obtained with the method described in the previous paragraph.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{<div}\OtherTok{ id=}\StringTok{"htmlwidget_container"}\KeywordTok{>}
  \KeywordTok{<div} 
\OtherTok{    id=}\StringTok{"htmlwidget-c21cca0e76e520b46fc7"} 
\OtherTok{    style=}\StringTok{"width:960px;height:500px;"} 
\OtherTok{    class=}\StringTok{"play html-widget"}\KeywordTok{>}
\NormalTok{    This is a widget!}
  \KeywordTok{</div>}
\KeywordTok{</div>}
\KeywordTok{<script} 
\OtherTok{  type=}\StringTok{"application/json"} 
\OtherTok{  data-for=}\StringTok{"htmlwidget-c21cca0e76e520b46fc7"}\KeywordTok{>}
  \OperatorTok{\{}\StringTok{"x"}\OperatorTok{:\{}\StringTok{"message"}\OperatorTok{:}\StringTok{"This is a widget!"}\OperatorTok{\},}\StringTok{"evals"}\OperatorTok{:}\NormalTok{[]}\OperatorTok{,}\StringTok{"jsHooks"}\OperatorTok{:}\NormalTok{[]}\OperatorTok{\}}
\KeywordTok{</script>}
\end{Highlighting}
\end{Shaded}

One thing the source code of the rendered output reveals is the element (\texttt{\textless{}div\textgreater{}}) created by the htmlwidgets package to hold the message (the class name is identical to that of the widget, \texttt{play}), as well as, below it, in the \texttt{\textless{}script\textgreater{}} tag, the JSON\index{JSON} object which includes the \texttt{x} variable used in the \texttt{play} function. The \texttt{div} created bears a randomly generated \texttt{id} which one can define when creating the widget using the \texttt{elementId} argument.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# specify the id}
\KeywordTok{play}\NormalTok{(}\StringTok{"This is another widget"}\NormalTok{, }\DataTypeTok{elementId =} \StringTok{"myViz"}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{<!-- div bears id specified in R -->}
\KeywordTok{<div}\OtherTok{ id=}\StringTok{"myViz"} 
\OtherTok{  style=}\StringTok{"width:960px;height:500px;"} 
\OtherTok{  class=}\StringTok{"play html-widget"}\KeywordTok{>}
\NormalTok{  This is another widget}
\KeywordTok{</div>}
\end{Highlighting}
\end{Shaded}

You will also notice that this affects the \texttt{script} tag below it, the \texttt{data-for} attribute of which is also set to ``myViz;'' this indicates that it is used to tie the JSON\index{JSON} data to a \texttt{div}, essential for htmlwidgets to manage multiple visualisations in R markdown\index{R markdown} or Shiny for instance. Then again, this happens in the background without the developer (you) having to worry about it.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{<script}\OtherTok{ type=}\StringTok{"application/json"} 
\OtherTok{  data-for=}\StringTok{"myViz"}\KeywordTok{>}
  \OperatorTok{\{}\StringTok{"x"}\OperatorTok{:\{}\StringTok{"message"}\OperatorTok{:}\StringTok{"This is a widget!"}\OperatorTok{\},}\StringTok{"evals"}\OperatorTok{:}\NormalTok{[]}\OperatorTok{,}\StringTok{"jsHooks"}\OperatorTok{:}\NormalTok{[]}\OperatorTok{\}}
\KeywordTok{</script>}
\end{Highlighting}
\end{Shaded}

Inspecting the output also shows the dependencies\index{dependency} imported, these are placed within the \texttt{head} HTML tags at the top of the page.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{<script}\OtherTok{ src=}\StringTok{"lib/htmlwidgets-1.5.1/htmlwidgets.js"}\KeywordTok{></script>}
\KeywordTok{<script}\OtherTok{ src=}\StringTok{"lib/play-binding-0.0.0.9000/play.js"}\KeywordTok{></script>}
\end{Highlighting}
\end{Shaded}

This effectively imports the \texttt{htmlwidgets.js} library and the \texttt{play.js} file, were the visualisation depending on external libraries they would appear alongside those JavaScript files.

\hypertarget{widgets-first-js-files}{%
\section{JavaScript Files}\label{widgets-first-js-files}}

Peaking inside the \texttt{play.js} file located at \texttt{inst/htmlwidgets/play.js} reveals the following code:

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{// play.js}
\VariableTok{HTMLWidgets}\NormalTok{.}\AttributeTok{widget}\NormalTok{(}\OperatorTok{\{}

  \DataTypeTok{name}\OperatorTok{:} \StringTok{'play'}\OperatorTok{,}

  \DataTypeTok{type}\OperatorTok{:} \StringTok{'output'}\OperatorTok{,}

  \DataTypeTok{factory}\OperatorTok{:} \KeywordTok{function}\NormalTok{(el}\OperatorTok{,}\NormalTok{ width}\OperatorTok{,}\NormalTok{ height) }\OperatorTok{\{}

    \CommentTok{// }\AlertTok{TODO}\CommentTok{: define shared variables for this instance}

    \ControlFlowTok{return} \OperatorTok{\{}

      \DataTypeTok{renderValue}\OperatorTok{:} \KeywordTok{function}\NormalTok{(x) }\OperatorTok{\{}

        \CommentTok{// }\AlertTok{TODO}\CommentTok{: code to render the widget, e.g.}
        \VariableTok{el}\NormalTok{.}\AttributeTok{innerText} \OperatorTok{=} \VariableTok{x}\NormalTok{.}\AttributeTok{message}\OperatorTok{;}

      \OperatorTok{\},}

      \DataTypeTok{resize}\OperatorTok{:} \KeywordTok{function}\NormalTok{(width}\OperatorTok{,}\NormalTok{ height) }\OperatorTok{\{}

        \CommentTok{// }\AlertTok{TODO}\CommentTok{: code to re-render the widget with a new size}

      \OperatorTok{\}}

    \OperatorTok{\};}
  \OperatorTok{\}}
\OperatorTok{\}}\NormalTok{)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

However convoluted this may appear at first, do not let that intimidate you. The name of the widget (\texttt{play}) corresponds to the name used to generate the scaffold\index{scaffold}, it can also be seen in the \texttt{createWidget} function used inside the \texttt{play.R} file.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{htmlwidgets}\OperatorTok{::}\KeywordTok{createWidget}\NormalTok{(}
  \DataTypeTok{name =} \StringTok{'play'}\NormalTok{,}
\NormalTok{  x,}
  \DataTypeTok{width =}\NormalTok{ width,}
  \DataTypeTok{height =}\NormalTok{ height,}
  \DataTypeTok{package =} \StringTok{'playground'}\NormalTok{,}
  \DataTypeTok{elementId =}\NormalTok{ elementId}
\NormalTok{)}
\end{Highlighting}
\end{Shaded}

This is so htmlwidgets\index{htmlwidgets} can internally match the output of \texttt{createWidget} to its JavaScript function. At this stage, it is probably fair to take a look at the diagram (Figure \ref{fig:widget-internals-diagram}) of what is happening.

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/03-htmlwidgets-internals} 

}

\caption{htmlwidgets internals visualised}\label{fig:widget-internals-diagram}
\end{figure}

The \texttt{factory} function returns two functions, \texttt{resize} and \texttt{renderValue}. The first is used to resize\index{resize} the output dynamically; it is not relevant to this widget and is thus tackled later on. Let us focus on \texttt{renderValue}, the function that renders the output. It takes an object \texttt{x} from which the ``message'' variable is used as the text for object \texttt{el} (\texttt{el.innerText}). The object \texttt{x} passed to this function is actually the list of the same name that was built in the R function \texttt{play}! While in R one would access the \texttt{message} in list \texttt{x} with \texttt{x\$message} in JavaScript to access the \texttt{message} in the JSON\index{JSON} \texttt{x} one writes \texttt{x.message}, only changing the dollar sign to a dot. Let us show this perhaps more clearly by printing the content of \texttt{x}.

\begin{Shaded}
\begin{Highlighting}[]
\VariableTok{console}\NormalTok{.}\AttributeTok{log}\NormalTok{(x)}\OperatorTok{;}
\VariableTok{el}\NormalTok{.}\AttributeTok{innerText} \OperatorTok{=} \VariableTok{x}\NormalTok{.}\AttributeTok{message}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

We place \texttt{console.log} to print the content of \texttt{x} in the console, reload the package with \texttt{devtools::load\_all} and use the function \texttt{play} again, then explore the console from the browser\index{web browser} (inspect and go to the ``console'' tab).

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/playground-console-x} 

}

\caption{Console log JavaScript object}\label{fig:playground-console}
\end{figure}

Firgure \ref{fig:playground-console} displays the JSON\index{JSON} object containing the message: it looks eerily similar to the list that was created in R (\texttt{x\ =\ list(message\ =\ "This\ is\ a\ widget!")}). What one should take away from this is that data that needs to be communicated from R to the JavaScript function should be placed in the R list \texttt{x}. This list is serialised\index{serialise} to JSON\index{JSON} and placed in the HTML\index{HTML} output in a \texttt{script} tag bearing a \texttt{data-for} attribute that indicates which widget the data is destined for. This effectively enables htmlwidgets to match the serialised data with the output elements: data in \texttt{\textless{}script\ data-for=\textquotesingle{}viz\textquotesingle{}\textgreater{}} is to be used to create a visualisation\index{visualisation} in \texttt{\textless{}div\ id=\textquotesingle{}viz\textquotesingle{}\textgreater{}}.

\begin{rmdnote}
Serialisation will make for an important section in a later chapter.
\end{rmdnote}

Before we move on to other things one should also grasp a better understanding of the \texttt{el} object, which can also be logged in the console.

\begin{Shaded}
\begin{Highlighting}[]
\VariableTok{console}\NormalTok{.}\AttributeTok{log}\NormalTok{(x)}\OperatorTok{;}
\VariableTok{console}\NormalTok{.}\AttributeTok{log}\NormalTok{(el)}\OperatorTok{;}
\VariableTok{el}\NormalTok{.}\AttributeTok{innerText} \OperatorTok{=} \VariableTok{x}\NormalTok{.}\AttributeTok{message}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/playground-console-el} 

}

\caption{Console log HTML element}\label{fig:playground-console-el}
\end{figure}

Figure \ref{fig:playground-console-el} displays the HTML element created by htmlwidgets that is meant to hold the visualisation or, in this case, the message. If you are familiar with JavaScript, this is the element that would be returned by \texttt{document.getElementById}. This object allows manipulating the element in pretty much any way imaginable: change its position, its colour, its size, or, as done here, insert some text within it. What's more one can access attributes of the object just like a JSON\index{JSON} array. Therefore, one can log the \texttt{id} of the element.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{// print the id of the element}
\VariableTok{console}\NormalTok{.}\AttributeTok{log}\NormalTok{(}\VariableTok{el}\NormalTok{.}\AttributeTok{id}\NormalTok{)}\OperatorTok{;}
\VariableTok{el}\NormalTok{.}\AttributeTok{innerText} \OperatorTok{=} \VariableTok{x}\NormalTok{.}\AttributeTok{message}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

Making the modifications above and reloading the package, one can create a widget given a specific id and see it displayed in the console, e.g.: \texttt{play("hello",\ elementId\ =\ "see-you-in-the-console")}.

In an attempt to become more at ease with this setup, let us change something and play with the widget. Out-of-the-box htmlwidgets\index{htmlwidgets} uses \texttt{innerText}, which does very much what it says on the tin, it places text inside an element. JavaScript comes with another function akin to \texttt{innerText}, \texttt{innerHTML}. While the former only allows inserting text, the latter lets one insert any HTML\index{HTML}.

\begin{Shaded}
\begin{Highlighting}[]
\VariableTok{el}\NormalTok{.}\AttributeTok{innerHTML} \OperatorTok{=} \VariableTok{x}\NormalTok{.}\AttributeTok{message}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

After changing the \texttt{play.js} file as above, and re-loading the package, one can use arbitrary HTML\index{HTML} as messages as shown in Figure \ref{fig:playground-h1}.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{play}\NormalTok{(}\StringTok{"<h1>Using HTML!</h1>"}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/playground-h1} 

}

\caption{First widget output}\label{fig:playground-h1}
\end{figure}

That makes for a significant improvement, which opens the door to many possibilities. However, the interface this provides is unintuitive. Albeit similar, R users are more familiar with Shiny and htmltools \citep{R-htmltools} tags than HTML tags, e.g.: \texttt{\textless{}h1\textgreater{}\textless{}/h1\textgreater{}} translates to \texttt{h1()} in R. The package should allow users to use those instead of forcing them to collapse HTML content in a string. Fortunately, there is an effortless way to obtain the HTML from those functions: convert it to a character string.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{html <-}\StringTok{ }\NormalTok{shiny}\OperatorTok{::}\KeywordTok{h1}\NormalTok{(}\StringTok{"HTML tag"}\NormalTok{)}

\KeywordTok{class}\NormalTok{(html)}
\CommentTok{#> [1] "shiny.tag"}

\CommentTok{# returns string}
\KeywordTok{as.character}\NormalTok{(html)}
\CommentTok{#> [1] "<h1>HTML tag</h1>"}
\end{Highlighting}
\end{Shaded}

Implementing this in the \texttt{play} function will look like this.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# forward options using x}
\NormalTok{x =}\StringTok{ }\KeywordTok{list}\NormalTok{(}
  \DataTypeTok{message =} \KeywordTok{as.character}\NormalTok{(message)}
\NormalTok{)}
\end{Highlighting}
\end{Shaded}

Reloading the package with \texttt{devtools::load\_all} lets one use Shiny tags as the message as demonstrated in Figure \ref{fig:playground-tags}.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{play}\NormalTok{(}
\NormalTok{  shiny}\OperatorTok{::}\KeywordTok{h2}\NormalTok{(}\StringTok{"Chocolate is a colour"}\NormalTok{, }\DataTypeTok{style =} \StringTok{"color:chocolate;"}\NormalTok{)}
\NormalTok{)}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/playground-color} 

}

\caption{First widget using Shiny tags}\label{fig:playground-tags}
\end{figure}

This hopefully provides some understanding of how htmlwidgets work internally and thereby helps to build such packages. To recapitulate, an HTML\index{HTML} document is created in which div is placed and given a specific id; this id is also used in a script tag that contains JSON data passed from R so that a JavaScript function we define can read that data in and use it to generate a visual output in a div. However, as much as this section covered, the topic of JavaScript dependencies\index{dependency} was not touched, this is approached in the following section where we build another, more exciting widget, which uses an external dependency.

\hypertarget{widgets-realistic}{%
\chapter{A Realistic Widget}\label{widgets-realistic}}

In this section, we build a package called \texttt{peity}, which wraps the JavaScript library of the same name, \href{https://github.com/benpickles/peity}{peity.js}, to create inline charts. This builds upon many things we explored in the playground package built in the previous chapter.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{usethis}\OperatorTok{::}\KeywordTok{create_package}\NormalTok{(}\StringTok{"peity"}\NormalTok{)}
\NormalTok{htmlwidgets}\OperatorTok{::}\KeywordTok{scaffoldWidget}\NormalTok{(}\StringTok{"peity"}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

As done with candidate libraries, as explained in an earlier chapter, there is no avoiding going through the documentation of the library one wants to use to observe how it works. Forging a basic understanding of the library, we can build the following basic example.

\begin{Shaded}
\begin{Highlighting}[]
\DataTypeTok{<!DOCTYPE }\NormalTok{html}\DataTypeTok{>}
\KeywordTok{<html}\OtherTok{ xmlns=}\StringTok{"http://www.w3.org/1999/xhtml"}\OtherTok{ lang=}\StringTok{""}\OtherTok{ xml:lang=}\StringTok{""}\KeywordTok{>}

\KeywordTok{<head>}
  \CommentTok{<!-- Import libraries -->}
  \KeywordTok{<script}\OtherTok{ src=}\StringTok{"jquery-3.5.1.min.js"}\KeywordTok{></script>}
  \KeywordTok{<script}\OtherTok{ src=}\StringTok{"jquery.peity.min.js"}\KeywordTok{></script>}
\KeywordTok{</head>}

\KeywordTok{<body>}
  \CommentTok{<!-- div to hold visualisation -->}
  \KeywordTok{<span}\OtherTok{ id=}\StringTok{"bar"}\KeywordTok{>}\NormalTok{5,3,9,6,5,9,7,3,5,2}\KeywordTok{</span>}

  \CommentTok{<!-- Script to create visualisation -->}
  \KeywordTok{<script>}
    \AttributeTok{$}\NormalTok{(}\StringTok{"#bar"}\NormalTok{).}\AttributeTok{peity}\NormalTok{(}\StringTok{"bar"}\NormalTok{)}\OperatorTok{;}
  \KeywordTok{</script>}
\KeywordTok{</body>}

\KeywordTok{</html>}
\end{Highlighting}
\end{Shaded}

Peity.js depends on jQuery\index{jQuery}. Hence the latter is imported first; the data for the chart is placed in a \texttt{\textless{}span\textgreater{}}, and the \texttt{peity} method is then used on the element containing the data. Peity.js uses \texttt{\textless{}span\textgreater{}} HTML\index{HTML} tags as these work inline, using a \texttt{\textless{}div\textgreater{}} the chart will still display, but the purpose of using peity.js would be defeated.

\hypertarget{widgets-realistic-deps}{%
\section{Dependencies}\label{widgets-realistic-deps}}

Once the package is created and the widget scaffold\index{scaffold} laid down, we need to add the JavaScript dependencies\index{dependency} without which nothing can move forward.

Two dependencies\index{dependency} are required in order for peity.js to run: peity.js and jQuery\index{jQuery}. Instead of using the CDN\index{CDN} those are downloaded as this ultimately makes the package more robust (more easily reproducible outputs and no requirement for internet connection). Each of the two libraries is placed in its own respective directory.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{dir.create}\NormalTok{(}\StringTok{"./inst/htmlwidgets/jquery"}\NormalTok{)}
\KeywordTok{dir.create}\NormalTok{(}\StringTok{"./inst/htmlwidgets/peity"}\NormalTok{)}

\NormalTok{peity <-}\StringTok{ }\KeywordTok{paste0}\NormalTok{(}
  \StringTok{"https://raw.githubusercontent.com/benpickles/"}\NormalTok{,}
  \StringTok{"peity/master/jquery.peity.min.js"}
\NormalTok{)}
\NormalTok{jquery <-}\StringTok{ }\KeywordTok{paste0}\NormalTok{(}
  \StringTok{"https://code.jquery.com/jquery-3.5.1.min.js"}
\NormalTok{)}

\KeywordTok{download.file}\NormalTok{(}
\NormalTok{  jquery, }\StringTok{"./inst/htmlwidgets/jquery/jquery.min.js"}
\NormalTok{)}
\KeywordTok{download.file}\NormalTok{(}
\NormalTok{  peity, }\StringTok{"./inst/htmlwidgets/peity/jquery.peity.min.js"}
\NormalTok{)}
\end{Highlighting}
\end{Shaded}

This produces a directory that looks like this:

\begin{verbatim}
.
├── DESCRIPTION
├── NAMESPACE
├── R
│   └── peity.R
└── inst
    └── htmlwidgets
        ├── jquery
        │   └── jquery.min.js
        ├── peity.js
        ├── peity.yaml
        └── peity
            └── jquery.peity.min.js
\end{verbatim}

In htmlwidgets, dependencies\index{dependency} are specified in the \texttt{.yaml} file located at \texttt{inst/htmlwidgets}, which at first contains a commented template.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# (uncomment to add a dependency)}
\CommentTok{# dependencies:}
\CommentTok{#  - name:}
\CommentTok{#    version:}
\CommentTok{#    src:}
\CommentTok{#    script:}
\CommentTok{#    stylesheet:}
\end{Highlighting}
\end{Shaded}

Let's uncomment those lines as instructed at the top of the file and fill it in.

\begin{Shaded}
\begin{Highlighting}[]
\FunctionTok{dependencies:}
  \KeywordTok{-} \FunctionTok{name:}\AttributeTok{ jQuery}
    \FunctionTok{version:}\AttributeTok{ }\FloatTok{3.5.1}
    \FunctionTok{src:}\AttributeTok{ htmlwidgets/jquery}
    \FunctionTok{script:}\AttributeTok{ jquery.min.js}
  \KeywordTok{-} \FunctionTok{name:}\AttributeTok{ peity}
    \FunctionTok{version:}\AttributeTok{ }\FloatTok{3.3.0}
    \FunctionTok{src:}\AttributeTok{ htmlwidgets/peity}
    \FunctionTok{script:}\AttributeTok{ jquery.peity.min.js}
\end{Highlighting}
\end{Shaded}

\begin{rmdnote}
The order of the dependencies matters. Peity.js depends on
jQuery\index{jQuery} hence the latter comes first in the \texttt{.yaml}.
\end{rmdnote}

The order in which one specifies the dependencies\index{dependency} matters, just like it does in an HTML file, therefore jQuery\index{jQuery} is listed first. The \texttt{stylesheet} entries were removed as none of these libraries require CSS files. The \texttt{src} path points to the directory containing the JavaScript files and stylesheets relative to the \texttt{inst} directory of the package; this is akin to using the \texttt{system.file} function to return the full path to a file or directory within the package.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{devtools}\OperatorTok{::}\KeywordTok{load_all}\NormalTok{()}
\KeywordTok{system.file}\NormalTok{(}\StringTok{"htmlwidgets/peity"}\NormalTok{, }\DataTypeTok{package =} \StringTok{"peity"}\NormalTok{)                                         }
\CommentTok{#> "/home/me/packages/peity/inst/htmlwidgets/peity"}
\end{Highlighting}
\end{Shaded}

We should verify that this is correct by using the one R function the package features and check the source code of the output to verify that the dependencies\index{dependency} are well present in the HTML output. We thus run \texttt{peity("test")}, open the output in the browser (\includegraphics{images/open-in-browser.png}) and look at the source code of the page. At the top of the page, you should see \texttt{jquery.min.js} and \texttt{jquery.peity.min.js} imported, clicking those links will either present you with the content of the file or an error.

\begin{Shaded}
\begin{Highlighting}[]
\DataTypeTok{<!DOCTYPE }\NormalTok{html}\DataTypeTok{>}
\KeywordTok{<html>}
\KeywordTok{<head>}
\KeywordTok{<meta}\OtherTok{ charset=}\StringTok{"utf-8"}\KeywordTok{/>}
\KeywordTok{<style>}\NormalTok{body\{}\KeywordTok{background-color}\NormalTok{:}\ConstantTok{white}\OperatorTok{;}\NormalTok{\}}\KeywordTok{</style>}
\KeywordTok{<script}\OtherTok{ src=}\StringTok{"lib/htmlwidgets-1.5.1/htmlwidgets.js"}\KeywordTok{></script>}
\KeywordTok{<script}\OtherTok{ src=}\StringTok{"lib/jQuery-3.5.1/jquery.min.js"}\KeywordTok{></script>}
\KeywordTok{<script}\OtherTok{ src=}\StringTok{"lib/peity-3.3.0/jquery.peity.min.js"}\KeywordTok{></script>}
\KeywordTok{<script}\OtherTok{ src=}\StringTok{"lib/peity-binding-0.0.0.9000/peity.js"}\KeywordTok{></script>}
\NormalTok{...}
\end{Highlighting}
\end{Shaded}

\hypertarget{widgets-realistic-implementation}{%
\section{Implementation}\label{widgets-realistic-implementation}}

The JavaScript code for peity.js is relatively uncomplicated. It is just one function, but integrating it with htmlwidgets requires some thinking. In the example below, peity is applied to the element with \texttt{id\ =\ \textquotesingle{}elementId\textquotesingle{}}; the first argument of \texttt{peity} is the type of chart to produce from the data, and the second optional argument is a JSON of options.

\begin{Shaded}
\begin{Highlighting}[]
\AttributeTok{$}\NormalTok{(}\StringTok{"#elementId"}\NormalTok{).}\AttributeTok{peity}\NormalTok{(}\StringTok{"bar"}\OperatorTok{,} \OperatorTok{\{}
  \DataTypeTok{fill}\OperatorTok{:}\NormalTok{ [}\StringTok{"red"}\OperatorTok{,} \StringTok{"green"}\OperatorTok{,} \StringTok{"blue"}\NormalTok{]}
\OperatorTok{\}}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

Also, the data that peity uses to draw the inline chart is not passed to the function but taken from the HTML element.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{<span}\OtherTok{ id=}\StringTok{"elementId"}\KeywordTok{>}\NormalTok{5,3,9,6}\KeywordTok{</span>}
\end{Highlighting}
\end{Shaded}

Therefore, the htmlwidget will have to insert the data in the HTML element, then run the \texttt{peity} function to render the chart. Inserting the data is actually already done by htmlwidgets by default. Indeed the default htmlwidgets template takes a \texttt{message} from the R function, and inserts said message in the HTML element, passing a vector instead of a message produces precisely what peity expects!

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{peity}\NormalTok{(}\KeywordTok{c}\NormalTok{(}\DecValTok{1}\NormalTok{,}\DecValTok{5}\NormalTok{,}\DecValTok{6}\NormalTok{,}\DecValTok{2}\NormalTok{))}
\end{Highlighting}
\end{Shaded}

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{<div} 
\OtherTok{  id=}\StringTok{"htmlwidget-495cf47d1a2a4a56c851"} 
\OtherTok{  style=}\StringTok{"width:960px;height:500px;"} 
\OtherTok{  class=}\StringTok{"play html-widget"}\KeywordTok{>}
\NormalTok{  1,5,6,2}
\KeywordTok{</div>}
\end{Highlighting}
\end{Shaded}

The argument ought to be renamed nonetheless from \texttt{message} to \texttt{data}.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{peity <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(data, }\DataTypeTok{width =} \OtherTok{NULL}\NormalTok{, }\DataTypeTok{height =} \OtherTok{NULL}\NormalTok{, }
  \DataTypeTok{elementId =} \OtherTok{NULL}\NormalTok{) \{}

  \CommentTok{# forward options using x}
\NormalTok{  x =}\StringTok{ }\KeywordTok{list}\NormalTok{(}
    \DataTypeTok{data =}\NormalTok{ data}
\NormalTok{  )}

  \CommentTok{# create widget}
\NormalTok{  htmlwidgets}\OperatorTok{::}\KeywordTok{createWidget}\NormalTok{(}
    \DataTypeTok{name =} \StringTok{'peity'}\NormalTok{,}
\NormalTok{    x,}
    \DataTypeTok{width =}\NormalTok{ width,}
    \DataTypeTok{height =}\NormalTok{ height,}
    \DataTypeTok{package =} \StringTok{'peity'}\NormalTok{,}
    \DataTypeTok{elementId =}\NormalTok{ elementId}
\NormalTok{  )}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

The change in the R code must be mirrored in the \texttt{peity.js} file, where it should set the \texttt{innerText} to \texttt{x.data} instead of \texttt{x.message}.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{// peity.js}
\CommentTok{// el.innerText = x.message;}
\VariableTok{el}\NormalTok{.}\AttributeTok{innerText} \OperatorTok{=} \VariableTok{x}\NormalTok{.}\AttributeTok{data}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

This leaves the implementation of peity.js to turn the data into an actual chart. The way we shall go about it is to paste one of the examples in the \texttt{renderValue} function.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{renderValue}\OperatorTok{:} \KeywordTok{function}\NormalTok{(x) }\OperatorTok{\{}

  \CommentTok{// insert data}
  \VariableTok{el}\NormalTok{.}\AttributeTok{innerText} \OperatorTok{=} \VariableTok{x}\NormalTok{.}\AttributeTok{data}\OperatorTok{;}

  \CommentTok{// run peity}
  \AttributeTok{$}\NormalTok{(}\StringTok{"#elementId"}\NormalTok{).}\AttributeTok{peity}\NormalTok{(}\StringTok{"bar"}\OperatorTok{,} \OperatorTok{\{}
    \DataTypeTok{fill}\OperatorTok{:}\NormalTok{ [}\StringTok{"red"}\OperatorTok{,} \StringTok{"green"}\OperatorTok{,} \StringTok{"blue"}\NormalTok{]}
  \OperatorTok{\}}\NormalTok{)}

\OperatorTok{\}}
\end{Highlighting}
\end{Shaded}

One could be tempted to run \texttt{devtools::load\_all}, but this will not work, namely because the function uses a selector that will not return any object; it needs to be applied to the div created by the widget not \texttt{\#elementId}. As explained in the previous chapter, the selector of the element created is accessible from the \texttt{el} object. As a matter of fact, we did log in the browser console the id of the created div taken from \texttt{el.id}. Therefore concatenating the pound sign and the element id produces the selector to said element (\texttt{.class}, \texttt{\#id}).

\begin{Shaded}
\begin{Highlighting}[]
\AttributeTok{$}\NormalTok{(}\StringTok{"#"} \OperatorTok{+} \VariableTok{el}\NormalTok{.}\AttributeTok{id}\NormalTok{).}\AttributeTok{peity}\NormalTok{(}\StringTok{"bar"}\OperatorTok{,} \OperatorTok{\{}
  \DataTypeTok{fill}\OperatorTok{:}\NormalTok{ [}\StringTok{"red"}\OperatorTok{,} \StringTok{"green"}\OperatorTok{,} \StringTok{"blue"}\NormalTok{]}
\OperatorTok{\}}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

This will work but can be further simplified; there is no need to recreate a selector using the \texttt{id} of the \texttt{el} element; the latter can be used in the jQuery\index{jQuery} selector directly.

\begin{Shaded}
\begin{Highlighting}[]
\AttributeTok{$}\NormalTok{(el).}\AttributeTok{peity}\NormalTok{(}\StringTok{"bar"}\OperatorTok{,} \OperatorTok{\{}
  \DataTypeTok{fill}\OperatorTok{:}\NormalTok{ [}\StringTok{"red"}\OperatorTok{,} \StringTok{"green"}\OperatorTok{,} \StringTok{"blue"}\NormalTok{]}
\OperatorTok{\}}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

This will now produce a working widget, albeit limited to creating charts of a predefined type and colour. Next, these options defining the chart type, fill colours, and others must be made available from R.

Below we add a \texttt{type} argument to the \texttt{peity} function; this \texttt{type} argument is then forwarded to \texttt{x}, so it is serialised\index{serialise} and accessible in the JavaScript file.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{peity <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(data, }\DataTypeTok{type =} \KeywordTok{c}\NormalTok{(}\StringTok{"bar"}\NormalTok{, }\StringTok{"line"}\NormalTok{, }\StringTok{"pie"}\NormalTok{, }\StringTok{"donut"}\NormalTok{), }
  \DataTypeTok{width =} \OtherTok{NULL}\NormalTok{, }\DataTypeTok{height =} \OtherTok{NULL}\NormalTok{, }\DataTypeTok{elementId =} \OtherTok{NULL}\NormalTok{) \{}

\NormalTok{  type <-}\StringTok{ }\KeywordTok{match.arg}\NormalTok{(type)}

  \CommentTok{# forward options using x}
\NormalTok{  x =}\StringTok{ }\KeywordTok{list}\NormalTok{(}
    \DataTypeTok{data =}\NormalTok{ data,}
    \DataTypeTok{type =}\NormalTok{ type}
\NormalTok{  )}

  \CommentTok{# create widget}
\NormalTok{  htmlwidgets}\OperatorTok{::}\KeywordTok{createWidget}\NormalTok{(}
    \DataTypeTok{name =} \StringTok{'peity'}\NormalTok{,}
\NormalTok{    x,}
    \DataTypeTok{width =}\NormalTok{ width,}
    \DataTypeTok{height =}\NormalTok{ height,}
    \DataTypeTok{package =} \StringTok{'peity'}\NormalTok{,}
    \DataTypeTok{elementId =}\NormalTok{ elementId}
\NormalTok{  )}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

This should then be applied by replacing the hard-coded type (\texttt{"bar"}) to \texttt{x.type}.

\begin{Shaded}
\begin{Highlighting}[]
\AttributeTok{$}\NormalTok{(el).}\AttributeTok{peity}\NormalTok{(}\VariableTok{x}\NormalTok{.}\AttributeTok{type}\OperatorTok{,} \OperatorTok{\{}
  \DataTypeTok{fill}\OperatorTok{:}\NormalTok{ [}\StringTok{"red"}\OperatorTok{,} \StringTok{"green"}\OperatorTok{,} \StringTok{"blue"}\NormalTok{]}
\OperatorTok{\}}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

Reloading the package will now let one create a chart and define its type, but some options remain hard-coded. These can be made available from R in a variety of ways depending on the interface one wants to provide users of the package. Here we make them available via the three-dot construct (\texttt{...}), which are captured in a list and forwarded to the \texttt{x} object.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{peity <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(data, }\DataTypeTok{type =} \KeywordTok{c}\NormalTok{(}\StringTok{"bar"}\NormalTok{, }\StringTok{"line"}\NormalTok{, }\StringTok{"pie"}\NormalTok{, }\StringTok{"donut"}\NormalTok{), }
\NormalTok{  ..., }\DataTypeTok{width =} \OtherTok{NULL}\NormalTok{, }\DataTypeTok{height =} \OtherTok{NULL}\NormalTok{, }\DataTypeTok{elementId =} \OtherTok{NULL}\NormalTok{) \{}

\NormalTok{  type <-}\StringTok{ }\KeywordTok{match.arg}\NormalTok{(type)}

  \CommentTok{# forward options using x}
\NormalTok{  x =}\StringTok{ }\KeywordTok{list}\NormalTok{(}
    \DataTypeTok{data =}\NormalTok{ data,}
    \DataTypeTok{type =}\NormalTok{ type,}
    \DataTypeTok{options =} \KeywordTok{list}\NormalTok{(...)}
\NormalTok{  )}

  \CommentTok{# create widget}
\NormalTok{  htmlwidgets}\OperatorTok{::}\KeywordTok{createWidget}\NormalTok{(}
    \DataTypeTok{name =} \StringTok{'peity'}\NormalTok{,}
\NormalTok{    x,}
    \DataTypeTok{width =}\NormalTok{ width,}
    \DataTypeTok{height =}\NormalTok{ height,}
    \DataTypeTok{package =} \StringTok{'peity'}\NormalTok{,}
    \DataTypeTok{elementId =}\NormalTok{ elementId}
\NormalTok{  )}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

These can then be easily accessed from JavaScript.

\begin{Shaded}
\begin{Highlighting}[]
\AttributeTok{$}\NormalTok{(el).}\AttributeTok{peity}\NormalTok{(}\VariableTok{x}\NormalTok{.}\AttributeTok{type}\OperatorTok{,} \VariableTok{x}\NormalTok{.}\AttributeTok{options}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

This makes (nearly) all of the functionalities of peity.js available from R. Below we use \texttt{htmltools::browsable} to create multiple widgets at once, the function only accepts a single value, so the charts are wrapped in an \texttt{htmltools::tagList}. Let us explain those in reverse order, \texttt{tagList} accepts a group of tags or valid HTML\index{HTML} outputs like htmlwidgets\index{htmlwidgets} and wraps them into one, it is necessary here because the function \texttt{browsable} only accepts one value. Typically htmltools tags are just printed in the console; here we need them to be opened in the browser instead. Remember to run \texttt{devtools::load\_all} so you can run the \texttt{peity} function we just wrote.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(htmltools)}

\KeywordTok{browsable}\NormalTok{(}
  \KeywordTok{tagList}\NormalTok{(}
    \KeywordTok{peity}\NormalTok{(}\KeywordTok{runif}\NormalTok{(}\DecValTok{5}\NormalTok{)),}
    \KeywordTok{peity}\NormalTok{(}\KeywordTok{runif}\NormalTok{(}\DecValTok{5}\NormalTok{), }\DataTypeTok{type =} \StringTok{"line"}\NormalTok{),}
    \KeywordTok{peity}\NormalTok{(}\StringTok{"1/4"}\NormalTok{, }\DataTypeTok{type =} \StringTok{"pie"}\NormalTok{, }\DataTypeTok{fill =} \KeywordTok{c}\NormalTok{(}\StringTok{"#c6d9fd"}\NormalTok{, }\StringTok{"#4d89f9"}\NormalTok{)),}
    \KeywordTok{peity}\NormalTok{(}\KeywordTok{c}\NormalTok{(}\DecValTok{3}\NormalTok{,}\DecValTok{5}\NormalTok{), }\DataTypeTok{type =} \StringTok{"donut"}\NormalTok{)}
\NormalTok{  )}
\NormalTok{)}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/peity-div} 

}

\caption{Peity output with DIV}\label{fig:peity-divs}
\end{figure}

There is nonetheless one remaining issue in Figure \ref{fig:peity-divs}: peity.js is meant to create inline charts within \texttt{\textless{}span\textgreater{}} HTML\index{HTML} tags but these are created within \texttt{\textless{}div\textgreater{}} hence each chart appears on a new line.

\hypertarget{widgets-realistic-html-element}{%
\section{HTML Element}\label{widgets-realistic-html-element}}

As pointed out multiple times, the widget is generated in a \texttt{\textless{}div\textgreater{}}, which is working fine for most visualisation libraries. However, we saw that peity.js works best when placed in a \texttt{\textless{}span\textgreater{}} as this allows placing the charts inline.

This can be changed by placing a function named \texttt{widgetname\_html}, which is looked up by htmlwidgets and used if found. This is probably the first such function one encounters and is relatively uncommon, but it is literally how the htmlwidgets\index{htmlwidgets} package does it: it scans the namespace of the package looking for a function that starts with the name of the widget and ends in \texttt{\_html} and if found uses it. Otherwise, it uses the default \texttt{div}. This function takes the three-dot construct (\texttt{...}) and uses them in an htmltools tag. The three-dots are necessary because internally htmlwidgets need to be able to pass the \texttt{id}, \texttt{class}, and \texttt{style} attributes to the tag.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{peity_html <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(...)\{}
\NormalTok{  htmltools}\OperatorTok{::}\NormalTok{tags}\OperatorTok{$}\KeywordTok{span}\NormalTok{(...)}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

This can also come in handy if some arguments must be hard-coded, such as assigning a specific class to every widget.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{myWidget_html <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(..., class)\{}
\NormalTok{  htmltools}\OperatorTok{::}\NormalTok{tags}\OperatorTok{$}\KeywordTok{div}\NormalTok{(..., }\DataTypeTok{class =} \KeywordTok{c}\NormalTok{(class, }\StringTok{"my-class"}\NormalTok{))}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

Reloading the package after placing the function above anywhere in the package will produce inline charts, as show in Figure \ref{fig:peity-spans}.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{browsable}\NormalTok{(}
  \KeywordTok{tagList}\NormalTok{(}
    \KeywordTok{p}\NormalTok{(}
      \StringTok{"We can now"}\NormalTok{, }\KeywordTok{peity}\NormalTok{(}\KeywordTok{runif}\NormalTok{(}\DecValTok{5}\NormalTok{)),}
      \StringTok{"use peity"}\NormalTok{, }\KeywordTok{peity}\NormalTok{(}\KeywordTok{runif}\NormalTok{(}\DecValTok{5}\NormalTok{), }\DataTypeTok{type =} \StringTok{"line"}\NormalTok{),}
      \StringTok{"inline with text!"}\NormalTok{,}
      \KeywordTok{peity}\NormalTok{(}\KeywordTok{c}\NormalTok{(}\DecValTok{4}\NormalTok{,}\DecValTok{2}\NormalTok{), }\DataTypeTok{type =} \StringTok{"donut"}\NormalTok{)}
\NormalTok{    )}
\NormalTok{  )}
\NormalTok{)}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/peity-span} 

}

\caption{Peity output with SPAN}\label{fig:peity-spans}
\end{figure}

\hypertarget{widgets-full}{%
\chapter{The Full Monty}\label{widgets-full}}

With a first widget built, one can jump onto another one: \href{https://giojs.org/}{gio.js}, a library to draw arcs between countries on a three-dimensional globe. This will include many more functionalities such packages can comprise.

Then again, the first order of business when looking to integrate a library is to look at the documentation to understand what should be reproduced in R. Figure \ref{fig:gio-example} is a very basic example of using Gio.js in HTML.

\begin{Shaded}
\begin{Highlighting}[]
\DataTypeTok{<!DOCTYPE }\NormalTok{html}\DataTypeTok{>}
\KeywordTok{<html}\OtherTok{ xmlns=}\StringTok{"http://www.w3.org/1999/xhtml"}\OtherTok{ lang=}\StringTok{""}\OtherTok{ xml:lang=}\StringTok{""}\KeywordTok{>}

\KeywordTok{<head>}
  \CommentTok{<!-- Import libraries -->}
  \KeywordTok{<script}\OtherTok{ src=}\StringTok{"three.min.js"}\KeywordTok{></script>}
  \KeywordTok{<script}\OtherTok{ src=}\StringTok{"gio.min.js"}\KeywordTok{></script>}
\KeywordTok{</head>}

\KeywordTok{<body>}
  \CommentTok{<!-- div to hold visualisation -->}
  \KeywordTok{<div}\OtherTok{ id=}\StringTok{"globe"}\OtherTok{ style=}\StringTok{"width: 200px; height: 200px"}\KeywordTok{></div>}

  \CommentTok{<!-- Script to create visualisation -->}
  \KeywordTok{<script>}
    \KeywordTok{var}\NormalTok{ container }\OperatorTok{=} \VariableTok{document}\NormalTok{.}\AttributeTok{getElementById}\NormalTok{(}\StringTok{"globe"}\NormalTok{)}\OperatorTok{;}
    \KeywordTok{var}\NormalTok{ controller }\OperatorTok{=} \KeywordTok{new} \VariableTok{GIO}\NormalTok{.}\AttributeTok{Controller}\NormalTok{(container)}\OperatorTok{;}
    \VariableTok{controller}\NormalTok{.}\AttributeTok{addData}\NormalTok{(data)}\OperatorTok{;}
    \VariableTok{controller}\NormalTok{.}\AttributeTok{init}\NormalTok{()}\OperatorTok{;}
  \KeywordTok{</script>}
\KeywordTok{</body>}

\KeywordTok{</html>}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/gio-example} 

}

\caption{Gio.js example}\label{fig:gio-example}
\end{figure}

Gio.js has itself a dependency\index{dependency}, \href{https://threejs.org/}{three.js}, which needs to be imported before gio.js, other than that not much differs from libraries previously explored in this chapter.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{usethis}\OperatorTok{::}\KeywordTok{create_package}\NormalTok{(}\StringTok{"gio"}\NormalTok{)}
\NormalTok{htmlwidgets}\OperatorTok{::}\KeywordTok{scaffoldWidget}\NormalTok{(}\StringTok{"gio"}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

\hypertarget{widgets-full-deps}{%
\section{Dependencies}\label{widgets-full-deps}}

Handling the dependencies\index{dependency} does not differ much, we create the directories within the \texttt{inst} path and download the dependencies within them.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# create directories for JS dependencies}
\KeywordTok{dir.create}\NormalTok{(}\StringTok{"./inst/htmlwidgets/three"}\NormalTok{, }\DataTypeTok{recursive =} \OtherTok{TRUE}\NormalTok{)}
\KeywordTok{dir.create}\NormalTok{(}\StringTok{"./inst/htmlwidgets/gio"}\NormalTok{, }\DataTypeTok{recursive =} \OtherTok{TRUE}\NormalTok{)}

\CommentTok{# download JS dependencies}
\NormalTok{three <-}\StringTok{ }\KeywordTok{paste0}\NormalTok{(}
  \StringTok{"https://cdnjs.cloudflare.com/ajax/"}\NormalTok{,}
  \StringTok{"libs/three.js/110/three.min.js"}
\NormalTok{)}
\NormalTok{gio <-}\StringTok{ }\KeywordTok{paste0}\NormalTok{(}
  \StringTok{"https://raw.githubusercontent.com/"}\NormalTok{,}
  \StringTok{"syt123450/giojs/master/build/gio.min.js"}
\NormalTok{)}

\KeywordTok{download.file}\NormalTok{(three, }\StringTok{"./inst/htmlwidgets/three/three.min.js"}\NormalTok{)}
\KeywordTok{download.file}\NormalTok{(gio, }\StringTok{"./inst/htmlwidgets/gio/gio.min.js"}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

This should produce the following working directory.

\begin{verbatim}
.
├── DESCRIPTION
├── NAMESPACE
├── R
│   └── gio.R
└── inst
    └── htmlwidgets
        ├── gio
        │   └── gio.min.js
        ├── gio.js
        ├── gio.yaml
        └── three
            └── three.min.js
\end{verbatim}

The libraries have been downloaded, but the \texttt{gio.yml} file is yet to be edited. The order in which the libraries are listed matters. Just as in HTML, three.js needs to precede gio.js as the latter depends on the former and not vice versa.

\begin{Shaded}
\begin{Highlighting}[]
\FunctionTok{dependencies:}
  \KeywordTok{-} \FunctionTok{name:}\AttributeTok{ three}
    \FunctionTok{version:}\AttributeTok{ }\DecValTok{110}
    \FunctionTok{src:}\AttributeTok{ htmlwidgets/three}
    \FunctionTok{script:}\AttributeTok{ three.min.js}
  \KeywordTok{-} \FunctionTok{name:}\AttributeTok{ gio}
    \FunctionTok{version:}\AttributeTok{ }\FloatTok{2.0}
    \FunctionTok{src:}\AttributeTok{ htmlwidgets/gio}
    \FunctionTok{script:}\AttributeTok{ gio.min.js}
\end{Highlighting}
\end{Shaded}

\hypertarget{widgets-full-js}{%
\section{JavaScript}\label{widgets-full-js}}

Let's copy the JavaScript code from the \href{https://giojs.org/index.html}{Get Started section of gio.js} in the \texttt{gio.js} file's \texttt{renderValue} function. At this point, the data format is not known, so we comment the line, which adds data to the visualisation.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{// gio.js}
\VariableTok{HTMLWidgets}\NormalTok{.}\AttributeTok{widget}\NormalTok{(}\OperatorTok{\{}

  \DataTypeTok{name}\OperatorTok{:} \StringTok{'gio'}\OperatorTok{,}

  \DataTypeTok{type}\OperatorTok{:} \StringTok{'output'}\OperatorTok{,}

  \DataTypeTok{factory}\OperatorTok{:} \KeywordTok{function}\NormalTok{(el}\OperatorTok{,}\NormalTok{ width}\OperatorTok{,}\NormalTok{ height) }\OperatorTok{\{}

    \CommentTok{// }\AlertTok{TODO}\CommentTok{: define shared variables for this instance}

    \ControlFlowTok{return} \OperatorTok{\{}

      \DataTypeTok{renderValue}\OperatorTok{:} \KeywordTok{function}\NormalTok{(x) }\OperatorTok{\{}

        \KeywordTok{var}\NormalTok{ container }\OperatorTok{=} \VariableTok{document}\NormalTok{.}\AttributeTok{getElementById}\NormalTok{(}\StringTok{"globe"}\NormalTok{)}\OperatorTok{;}
        \KeywordTok{var}\NormalTok{ controller }\OperatorTok{=} \KeywordTok{new} \VariableTok{GIO}\NormalTok{.}\AttributeTok{Controller}\NormalTok{(container)}\OperatorTok{;}
        \CommentTok{//controller.addData(data);}
        \VariableTok{controller}\NormalTok{.}\AttributeTok{init}\NormalTok{()}\OperatorTok{;}

      \OperatorTok{\},}

      \DataTypeTok{resize}\OperatorTok{:} \KeywordTok{function}\NormalTok{(width}\OperatorTok{,}\NormalTok{ height) }\OperatorTok{\{}

        \CommentTok{// }\AlertTok{TODO}\CommentTok{: code to re-render the widget with a new size}

      \OperatorTok{\}}

    \OperatorTok{\};}
  \OperatorTok{\}}
\OperatorTok{\}}\NormalTok{)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

One can document and load the package, but it will not work as the code above attempts to place the visualisation in a \texttt{div} with \texttt{id\ =\ "globe"}. As for the previously-written widget, this needs to be changed to \texttt{el.id}.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{// gio.js}
\NormalTok{renderValue}\OperatorTok{:} \KeywordTok{function}\NormalTok{(x) }\OperatorTok{\{}

  \KeywordTok{var}\NormalTok{ container }\OperatorTok{=} \VariableTok{document}\NormalTok{.}\AttributeTok{getElementById}\NormalTok{(}\VariableTok{el}\NormalTok{.}\AttributeTok{id}\NormalTok{)}\OperatorTok{;}
  \KeywordTok{var}\NormalTok{ controller }\OperatorTok{=} \KeywordTok{new} \VariableTok{GIO}\NormalTok{.}\AttributeTok{Controller}\NormalTok{(container)}\OperatorTok{;}
  \CommentTok{//controller.addData(data);}
  \VariableTok{controller}\NormalTok{.}\AttributeTok{init}\NormalTok{()}\OperatorTok{;}

\OperatorTok{\}}
\end{Highlighting}
\end{Shaded}

At this stage, the widget should generate a visualisation (see Figure \ref{fig:gio-init}).

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{devtools}\OperatorTok{::}\KeywordTok{document}\NormalTok{()}
\NormalTok{devtools}\OperatorTok{::}\KeywordTok{load_all}\NormalTok{()}
\KeywordTok{gio}\NormalTok{(}\DataTypeTok{message =} \StringTok{"This required but not used"}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/gio-init} 

}

\caption{Gio output without data}\label{fig:gio-init}
\end{figure}

Not too shabby given how little work was put into this! Before we move on, let us optimise something. In the JavaScript code, we retrieve the \texttt{container} using \texttt{el.id}, but this in effect is very inefficient: \texttt{el} is identical to \texttt{container}.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{// gio.js}
\NormalTok{renderValue}\OperatorTok{:} \KeywordTok{function}\NormalTok{(x) }\OperatorTok{\{}

  \KeywordTok{var}\NormalTok{ controller }\OperatorTok{=} \KeywordTok{new} \VariableTok{GIO}\NormalTok{.}\AttributeTok{Controller}\NormalTok{(el)}\OperatorTok{;}
  \CommentTok{//controller.addData(data);}
  \VariableTok{controller}\NormalTok{.}\AttributeTok{init}\NormalTok{()}\OperatorTok{;}

\OperatorTok{\}}
\end{Highlighting}
\end{Shaded}

\hypertarget{widgets-full-data}{%
\section{Working with Data}\label{widgets-full-data}}

An exciting start, now onto adding data. Let us take a look at the \href{https://giojs.org/html/docs/dataAdd.html}{documentation} to see what data the library expects.

\begin{Shaded}
\begin{Highlighting}[]
\OtherTok{[}
  \FunctionTok{\{}
    \DataTypeTok{"e"}\FunctionTok{:} \StringTok{"CN"}\FunctionTok{,}
    \DataTypeTok{"i"}\FunctionTok{:} \StringTok{"US"}\FunctionTok{,}
    \DataTypeTok{"v"}\FunctionTok{:} \DecValTok{3300000}
  \FunctionTok{\}}\OtherTok{,}
  \FunctionTok{\{}
    \DataTypeTok{"e"}\FunctionTok{:} \StringTok{"CN"}\FunctionTok{,}
    \DataTypeTok{"i"}\FunctionTok{:} \StringTok{"RU"}\FunctionTok{,}
    \DataTypeTok{"v"}\FunctionTok{:} \DecValTok{10000}
  \FunctionTok{\}}
\OtherTok{]}
\end{Highlighting}
\end{Shaded}

The JSON\index{JSON} data should constitute arrays that denote arcs to draw on the globe where each arc is defined by an exporting country (\texttt{e}), an importing country (\texttt{i}), and is given a value (\texttt{v}). The importing and exporting country, the source and target of the arc, are indicated by ISO alpha-2 country codes. We can read this JSON into R.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# data.frame to test}
\NormalTok{arcs <-}\StringTok{ }\NormalTok{jsonlite}\OperatorTok{::}\KeywordTok{fromJSON}\NormalTok{(}
  \StringTok{'[}
\StringTok{    \{}
\StringTok{      "e": "CN",}
\StringTok{      "i": "US",}
\StringTok{      "v": 3300000}
\StringTok{    \},}
\StringTok{    \{}
\StringTok{      "e": "CN",}
\StringTok{      "i": "RU",}
\StringTok{      "v": 10000}
\StringTok{    \}}
\StringTok{  ]'}
\NormalTok{)}

\KeywordTok{print}\NormalTok{(arcs)}
\CommentTok{#>    e  i       v}
\CommentTok{#> 1 CN US 3300000}
\CommentTok{#> 2 CN RU   10000}
\end{Highlighting}
\end{Shaded}

Jsonlite automagically converts the JSON into a data frame where each row is an arc, which is excellent as R users tend to prefer rectangular data over lists: this is probably what the package should use as input too. Let us make some changes to the \texttt{gio} function, so it takes data as input.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{gio <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(data, }\DataTypeTok{width =} \OtherTok{NULL}\NormalTok{, }\DataTypeTok{height =} \OtherTok{NULL}\NormalTok{, }\DataTypeTok{elementId =} \OtherTok{NULL}\NormalTok{) \{}

  \CommentTok{# forward options using x}
\NormalTok{  x =}\StringTok{ }\KeywordTok{list}\NormalTok{(}
    \DataTypeTok{data =}\NormalTok{ data}
\NormalTok{  )}

  \CommentTok{# create widget}
\NormalTok{  htmlwidgets}\OperatorTok{::}\KeywordTok{createWidget}\NormalTok{(}
    \DataTypeTok{name =} \StringTok{'gio'}\NormalTok{,}
\NormalTok{    x,}
    \DataTypeTok{width =}\NormalTok{ width,}
    \DataTypeTok{height =}\NormalTok{ height,}
    \DataTypeTok{package =} \StringTok{'gio'}\NormalTok{,}
    \DataTypeTok{elementId =}\NormalTok{ elementId}
\NormalTok{  )}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

This must be reflected in the \texttt{play.js} file, where we uncomment the line previously commented and use \texttt{x.data} passed from R.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{// gio.js}
\NormalTok{renderValue}\OperatorTok{:} \KeywordTok{function}\NormalTok{(x) }\OperatorTok{\{}

  \KeywordTok{var}\NormalTok{ controller }\OperatorTok{=} \KeywordTok{new} \VariableTok{GIO}\NormalTok{.}\AttributeTok{Controller}\NormalTok{(el)}\OperatorTok{;}
  \VariableTok{controller}\NormalTok{.}\AttributeTok{addData}\NormalTok{(}\VariableTok{x}\NormalTok{.}\AttributeTok{data}\NormalTok{)}\OperatorTok{;} \CommentTok{// uncomment & use x.data}
  \VariableTok{controller}\NormalTok{.}\AttributeTok{init}\NormalTok{()}\OperatorTok{;}

\OperatorTok{\}}
\end{Highlighting}
\end{Shaded}

We can now use the function with the data to plot arcs!

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{devtools}\OperatorTok{::}\KeywordTok{document}\NormalTok{()}
\NormalTok{devtools}\OperatorTok{::}\KeywordTok{load_all}\NormalTok{()}
\KeywordTok{gio}\NormalTok{(arcs)}
\end{Highlighting}
\end{Shaded}

Unfortunately, this breaks everything, and we are presented with a blank screen. Using \texttt{console.log} or looking at the source code the rendered widget reveals the problem: the data is not actually in the correct format!

\begin{Shaded}
\begin{Highlighting}[]
\FunctionTok{\{}
  \DataTypeTok{"x"}\FunctionTok{:\{}
    \DataTypeTok{"data"}\FunctionTok{:\{}
      \DataTypeTok{"e"}\FunctionTok{:}\OtherTok{[}\StringTok{"CN"}\OtherTok{,}\StringTok{"CN"}\OtherTok{]}\FunctionTok{,}
      \DataTypeTok{"i"}\FunctionTok{:}\OtherTok{[}\StringTok{"US"}\OtherTok{,}\StringTok{"RU"}\OtherTok{]}\FunctionTok{,}
      \DataTypeTok{"v"}\FunctionTok{:}\OtherTok{[}\DecValTok{3300000}\OtherTok{,}\DecValTok{10000}\OtherTok{]}
    \FunctionTok{\}}
  \FunctionTok{\},}
  \DataTypeTok{"evals"}\FunctionTok{:}\OtherTok{[]}\FunctionTok{,}
  \DataTypeTok{"jsHooks"}\FunctionTok{:}\OtherTok{[]}
\FunctionTok{\}}
\end{Highlighting}
\end{Shaded}

Htmlwidgets serialised\index{serialise} the data frame column-wise (long), where each array is a column, whereas gio.js expect the data to be wide (row-wise serialisation), where each array is an arc (row).

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# column-wise}
\NormalTok{jsonlite}\OperatorTok{::}\KeywordTok{toJSON}\NormalTok{(arcs, }\DataTypeTok{dataframe =} \StringTok{"columns"}\NormalTok{)}
\CommentTok{#> \{"e":["CN","CN"],"i":["US","RU"],"v":[3300000,10000]\}}
\CommentTok{# row-wise}
\NormalTok{jsonlite}\OperatorTok{::}\KeywordTok{toJSON}\NormalTok{(arcs, }\DataTypeTok{dataframe =} \StringTok{"rows"}\NormalTok{)}
\CommentTok{#> [\{"e":"CN","i":"US","v":3300000\},\{"e":"CN","i":"RU","v":10000\}]}
\end{Highlighting}
\end{Shaded}

As mentioned previously, the convention has it that rectangular data (data frames) are serialised\index{serialise} row-wise. That is likely to be a recurring problem for many widgets.

\hypertarget{widgets-full-transform-data}{%
\section{Transforming Data}\label{widgets-full-transform-data}}

There are multiple ways to transform the data and ensure the serialised\index{serialise} JSON is as the JavaScript library expects it to be. The following sections explore those various methods before settling on a specific one for the gio package.

\hypertarget{widgets-full-transform-data-js}{%
\subsection{Using JavaScript}\label{widgets-full-transform-data-js}}

JavaScript can be used to transform the data, thereby leaving the serialiser as-is only to reshape it into the client. The htmlwidget JavaScript library (already imported by default) exports an object, which provides a method, \texttt{dataframeToD3}, to transform the data from long to wide.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{// gio.js}
\NormalTok{renderValue}\OperatorTok{:} \KeywordTok{function}\NormalTok{(x) }\OperatorTok{\{}

  \CommentTok{// long to wide}
  \VariableTok{x}\NormalTok{.}\AttributeTok{data} \OperatorTok{=} \VariableTok{HTMLWidgets}\NormalTok{.}\AttributeTok{dataframeToD3}\NormalTok{(}\VariableTok{x}\NormalTok{.}\AttributeTok{data}\NormalTok{)}\OperatorTok{;}

  \KeywordTok{var}\NormalTok{ controller }\OperatorTok{=} \KeywordTok{new} \VariableTok{GIO}\NormalTok{.}\AttributeTok{Controller}\NormalTok{(el)}\OperatorTok{;}
  \VariableTok{controller}\NormalTok{.}\AttributeTok{addData}\NormalTok{(}\VariableTok{x}\NormalTok{.}\AttributeTok{data}\NormalTok{)}\OperatorTok{;} 
  \VariableTok{controller}\NormalTok{.}\AttributeTok{init}\NormalTok{()}\OperatorTok{;}

\OperatorTok{\}}
\end{Highlighting}
\end{Shaded}

\hypertarget{widgets-full-transform-data-modify}{%
\subsection{Modify Serialiser}\label{widgets-full-transform-data-modify}}

Instead of serialising the data a certain way then correct it in JavaScript as demonstrated previously, one can also modify, or even replace the htmlwidgets default serialiser\index{serialise}. Speaking of which, below is the default serializer used by htmlwidgets.

\begin{Shaded}
\begin{Highlighting}[]
\ControlFlowTok{function}\NormalTok{ (x, ..., }\DataTypeTok{dataframe =} \StringTok{"columns"}\NormalTok{, }\DataTypeTok{null =} \StringTok{"null"}\NormalTok{, }
\DataTypeTok{na =} \StringTok{"null"}\NormalTok{, }\DataTypeTok{auto_unbox =} \OtherTok{TRUE}\NormalTok{, }\DataTypeTok{use_signif =} \OtherTok{TRUE}\NormalTok{, }
  \DataTypeTok{digits =} \KeywordTok{getOption}\NormalTok{(}\StringTok{"shiny.json.digits"}\NormalTok{, }\DecValTok{16}\NormalTok{), }\DataTypeTok{force =} \OtherTok{TRUE}\NormalTok{,}
  \DataTypeTok{POSIXt =} \StringTok{"ISO8601"}\NormalTok{, }\DataTypeTok{UTC =} \OtherTok{TRUE}\NormalTok{, }\DataTypeTok{rownames =} \OtherTok{FALSE}\NormalTok{, }
  \DataTypeTok{keep_vec_names =} \OtherTok{TRUE}\NormalTok{, }\DataTypeTok{strict_atomic =} \OtherTok{TRUE}\NormalTok{) }
\NormalTok{\{}
  \ControlFlowTok{if}\NormalTok{ (strict_atomic) }
\NormalTok{      x <-}\StringTok{ }\KeywordTok{I}\NormalTok{(x)}
\NormalTok{  jsonlite}\OperatorTok{::}\KeywordTok{toJSON}\NormalTok{(x, }\DataTypeTok{dataframe =}\NormalTok{ dataframe, }\DataTypeTok{null =}\NormalTok{ null, }\DataTypeTok{na =}\NormalTok{ na, }
    \DataTypeTok{auto_unbox =}\NormalTok{ auto_unbox, }\DataTypeTok{digits =}\NormalTok{ digits, }\DataTypeTok{force =}\NormalTok{ force, }
    \DataTypeTok{use_signif =}\NormalTok{ use_signif, }\DataTypeTok{POSIXt =}\NormalTok{ POSIXt, }\DataTypeTok{UTC =}\NormalTok{ UTC, }
    \DataTypeTok{rownames =}\NormalTok{ rownames, }\DataTypeTok{keep_vec_names =}\NormalTok{ keep_vec_names, }
    \DataTypeTok{json_verbatim =} \OtherTok{TRUE}\NormalTok{, ...)}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

The problem at hand is caused by the \texttt{data.frame} argument, which is set to \texttt{columns} where it should be set \texttt{rows} (for row-wise). Arguments are passed to the serialiser\index{serialise} indirectly, in the form of a list set as \texttt{TOJSON\_ARGS} attribute to the object \texttt{x} that is serialised\index{serialise}. We could thus change the \texttt{gio} function to reflect the aforementioned change.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{gio <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(data, }\DataTypeTok{width =} \OtherTok{NULL}\NormalTok{, }\DataTypeTok{height =} \OtherTok{NULL}\NormalTok{, }
  \DataTypeTok{elementId =} \OtherTok{NULL}\NormalTok{) \{}

  \CommentTok{# forward options using x}
\NormalTok{  x =}\StringTok{ }\KeywordTok{list}\NormalTok{(}
    \DataTypeTok{data =}\NormalTok{ data}
\NormalTok{  )}

  \CommentTok{# serialise data.frames to wide (not long as default)}
  \KeywordTok{attr}\NormalTok{(x, }\StringTok{'TOJSON_ARGS'}\NormalTok{) <-}\StringTok{ }\KeywordTok{list}\NormalTok{(}\DataTypeTok{dataframe =} \StringTok{"rows"}\NormalTok{)}

  \CommentTok{# create widget}
\NormalTok{  htmlwidgets}\OperatorTok{::}\KeywordTok{createWidget}\NormalTok{(}
    \DataTypeTok{name =} \StringTok{'gio'}\NormalTok{,}
\NormalTok{    x,}
    \DataTypeTok{width =}\NormalTok{ width,}
    \DataTypeTok{height =}\NormalTok{ height,}
    \DataTypeTok{package =} \StringTok{'gio'}\NormalTok{,}
    \DataTypeTok{elementId =}\NormalTok{ elementId}
\NormalTok{  )}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

The above may appear confusing at first as one rarely encounters the \texttt{attr} replacement function.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{attr}\NormalTok{(cars, }\StringTok{"hello"}\NormalTok{) <-}\StringTok{ "world"} \CommentTok{# set }
\KeywordTok{attr}\NormalTok{(cars, }\StringTok{"hello"}\NormalTok{) }\CommentTok{# get }
\CommentTok{#> [1] "world"}
\end{Highlighting}
\end{Shaded}

Other arguments can be placed in the same list; they will ultimately reach the serialiser to modify its output.

\hypertarget{widgets-full-transform-data-replace}{%
\subsection{Replace Serialiser}\label{widgets-full-transform-data-replace}}

Otherwise, the serialiser\index{serialise} can also be replaced in its entirety, also by setting an attribute, \texttt{TOJSON\_FUNC}, to the \texttt{x} object. Below the serialiser\index{serialise} is changed to jsonify \citep{R-jsonify}, which by default serialises data frames to wide, unlike htmlwidgets' serialiser, thereby also fixing the issue.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{gio <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(data, }\DataTypeTok{width =} \OtherTok{NULL}\NormalTok{, }\DataTypeTok{height =} \OtherTok{NULL}\NormalTok{, }
  \DataTypeTok{elementId =} \OtherTok{NULL}\NormalTok{) \{}

  \CommentTok{# forward options using x}
\NormalTok{  x =}\StringTok{ }\KeywordTok{list}\NormalTok{(}
    \DataTypeTok{data =}\NormalTok{ data}
\NormalTok{  )}

  \CommentTok{# replace serialiser}
  \KeywordTok{attr}\NormalTok{(x, }\StringTok{'TOJSON_FUNC'}\NormalTok{) <-}\StringTok{ }\NormalTok{gio_serialiser}

  \CommentTok{# create widget}
\NormalTok{  htmlwidgets}\OperatorTok{::}\KeywordTok{createWidget}\NormalTok{(}
    \DataTypeTok{name =} \StringTok{'gio'}\NormalTok{,}
\NormalTok{    x,}
    \DataTypeTok{width =}\NormalTok{ width,}
    \DataTypeTok{height =}\NormalTok{ height,}
    \DataTypeTok{package =} \StringTok{'gio'}\NormalTok{,}
    \DataTypeTok{elementId =}\NormalTok{ elementId}
\NormalTok{  )}
\NormalTok{\}}

\CommentTok{# serialiser}
\NormalTok{gio_serialiser <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(x)\{}
\NormalTok{  jsonify}\OperatorTok{::}\KeywordTok{to_json}\NormalTok{(x, }\DataTypeTok{unbox =} \OtherTok{TRUE}\NormalTok{)}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

\hypertarget{widgets-full-transform-data-modify-data}{%
\subsection{Modify the Data}\label{widgets-full-transform-data-modify-data}}

Alternatively, one can also leave all serialisers-related options unchanged and instead format the data in R prior to the serialisation, changing the dataframe to a row-wise list.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{x =}\StringTok{ }\KeywordTok{list}\NormalTok{(}
  \DataTypeTok{data =} \KeywordTok{apply}\NormalTok{(data, }\DecValTok{1}\NormalTok{, as.list)}
\NormalTok{)}
\end{Highlighting}
\end{Shaded}

The above would make it such that the serialiser no longer has to interpret how the data should be serialised (row-wise or column-wise), the data now being a list will be serialised correctly.

\hypertarget{widgets-full-transform-data-conclusion}{%
\subsection{Pros and Cons}\label{widgets-full-transform-data-conclusion}}

There are pros and cons to each method. The preferable method is probably to alter the default serialiser \textbf{only where needed}; this is the method used in the remainder of the book. Replacing the serialiser\index{serialise} in its entirety should not be necessary, only do this once you are very familiar with serialisation and truly see a need for it. Moreover, htmlwidgets' serialiser\index{serialise} extends jsonlite to allow converting JavaScript code, which will come in handy later on. Transforming the data in JavaScript has one drawback, \texttt{HTMLWidgets.dataframeToD3} cannot be applied to the entire \texttt{x} object, it will only work on the subsets that hold the column-wise data (\texttt{x.data}), which tends to lead to clunky code as one uses said function in various places.

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/gio-data} 

}

\caption{Gio output with correct serialisation}\label{fig:gio-data}
\end{figure}

Figure \ref{fig:gio-data} shows that the arcs correctly appear on the globe once the default serialiser has been modified.

\hypertarget{widgets-full-on-print}{%
\section{On Print Method}\label{widgets-full-on-print}}

Let us add the option to style the globe: gio.js provides multiple \href{https://giojs.org/html/docs/colorStyle.html}{themes} but they are currently not applicable from R. As a matter of fact, gio.js provides dozens of customisation options that should be available in the package as well. These, however, probably should be split across different functions, just like they are in gio.js, rather than all be accessible from a single function containing hundreds of arguments. This begs the question, when would one use another function given the function \texttt{gio} generates the visualisation? As it happens \texttt{gio} itself (or rather the function \texttt{htmlwidgets::createWidget} it contains) does not render the output; it returns an object of class ``htmlwidget,'' which renders the visualisation\index{visualisation} on print (literally \texttt{htmlwidget.print} method).

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{g <-}\StringTok{ }\KeywordTok{gio}\NormalTok{(arcs) }\CommentTok{# nothing renders}
\NormalTok{g }\CommentTok{# visualisation renders}
\end{Highlighting}
\end{Shaded}

Therefore, one can use functions on the object returned by \texttt{gio}, which contains, amongst other things, the \texttt{x} list to which we can make changes, append data, or do any other operation that standard R lists allow.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{print}\NormalTok{(g}\OperatorTok{$}\NormalTok{x)}

\CommentTok{## $data}
\CommentTok{##    e  i       v}
\CommentTok{## 1 CN US 3300000}
\CommentTok{## 2 CN RU   10000}
\CommentTok{## }
\CommentTok{## attr(,"TOJSON_ARGS")}
\CommentTok{## attr(,"TOJSON_ARGS")$dataframe}
\CommentTok{## [1] "rows"}
\end{Highlighting}
\end{Shaded}

This clarified, the function to change the style of the visualisation can be added to the package. It would take as input the output of \texttt{gio} and append the style (name of theme) to the \texttt{x} list; this would then be used in JavaScript to change the look of the visualisation.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{#' @export}
\NormalTok{gio_style <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(g, }\DataTypeTok{style =} \StringTok{"magic"}\NormalTok{)\{}
\NormalTok{  g}\OperatorTok{$}\NormalTok{x}\OperatorTok{$}\NormalTok{style <-}\StringTok{ }\NormalTok{style}
  \KeywordTok{return}\NormalTok{(g)}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

The style is applied using the \texttt{setStyle} method on the controller before the visualisation is created, before the \texttt{init} method is called, using the style passed from R: \texttt{x.style}.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{// gio.js}
\NormalTok{renderValue}\OperatorTok{:} \KeywordTok{function}\NormalTok{(x) }\OperatorTok{\{}

  \KeywordTok{var}\NormalTok{ controller }\OperatorTok{=} \KeywordTok{new} \VariableTok{GIO}\NormalTok{.}\AttributeTok{Controller}\NormalTok{(el)}\OperatorTok{;}
  \VariableTok{controller}\NormalTok{.}\AttributeTok{addData}\NormalTok{(}\VariableTok{x}\NormalTok{.}\AttributeTok{data}\NormalTok{)}\OperatorTok{;} 

  \VariableTok{controller}\NormalTok{.}\AttributeTok{setStyle}\NormalTok{(}\VariableTok{x}\NormalTok{.}\AttributeTok{style}\NormalTok{)}\OperatorTok{;} \CommentTok{// set style}

  \VariableTok{controller}\NormalTok{.}\AttributeTok{init}\NormalTok{()}\OperatorTok{;}

\OperatorTok{\}}
\end{Highlighting}
\end{Shaded}

We can now run \texttt{devtools::load\_all} to export the newly written function and load the functions in the environment\index{environment} with \texttt{devtools::load\_all} as shown in Figure \ref{fig:gio-style}.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{g1 <-}\StringTok{ }\KeywordTok{gio}\NormalTok{(arcs)}
\NormalTok{g2 <-}\StringTok{ }\KeywordTok{gio_style}\NormalTok{(g1, }\StringTok{"juicyCake"}\NormalTok{)}

\NormalTok{g2}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/gio-style} 

}

\caption{Gio with a new theme}\label{fig:gio-style}
\end{figure}

This is great but can be greatly improved upon with the magrittr pipe \citep{R-magrittr}\index{pipe}, it would allow effortlessly passing the output of each function to the next to obtain an API akin to that of plotly or highcharter.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(magrittr)}

\KeywordTok{gio}\NormalTok{(arcs) }\OperatorTok{%>%}\StringTok{ }
\StringTok{  }\KeywordTok{gio_style}\NormalTok{(}\StringTok{"juicyCake"}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

The pipe\index{pipe} drastically improves the API that gio provides its users and thus probably should be exported\index{export} by the package; the usethis package provides a function to do so easily.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# export the pipe}
\NormalTok{usethis}\OperatorTok{::}\KeywordTok{use_pipe}\NormalTok{()}
\end{Highlighting}
\end{Shaded}

This closes this chapter but is not the last we see of gio.js; we shall use it as an example in the next chapters as we extend its functionalities and polish certain aspects such as sizing and security.

\hypertarget{widgets-adv}{%
\chapter{Advanced Topics}\label{widgets-adv}}

In the previous chapter, we put together an attractive, fully-functioning widget, but it lacks polish and does not use all the features htmlwidgets provides; this chapter explores those. We look into handling the size of widgets to ensure they are responsive as well as discuss potential security concerns and how to address them. Finally, we show how to pass JavaScript code from R to JavaScript and how to add HTML\index{HTML} content before and after the widget.

\hypertarget{widgets-adv-shared}{%
\section{Shared Variables}\label{widgets-adv-shared}}

Up until now, the topic of shared variables had been omitted as it was not relevant. However, it will be from here onwards. Indeed we are about to discover how to manipulate the widget further; changing the data, resizing, and more. This will generally involve the JavaScript instance of the visualisation, the object named \texttt{controller} in the gio package, which, being defined in the \texttt{renderValue} function, is not accessible outside of it. To make it accessible outside of \texttt{renderValue} requires a tiny but consequential change without which resizing the widget will not be doable, for instance.

The \texttt{controller} variable has to be declared outside of the \texttt{renderValue} function, inside the \texttt{factory}. This was, in fact, indicated from the onset by the following comment: \texttt{//\ TODO:\ define\ shared\ variables\ for\ this\ instance} (generated by \texttt{htmlwidgets::scaffoldWidget}). Any variable declared as shown below will be accessible by all functions declared in the \texttt{factory}; \texttt{renderValue}, but also \texttt{resize} and others yet to be added.

\begin{Shaded}
\begin{Highlighting}[]
\VariableTok{HTMLWidgets}\NormalTok{.}\AttributeTok{widget}\NormalTok{(}\OperatorTok{\{}

  \DataTypeTok{name}\OperatorTok{:} \StringTok{'gio'}\OperatorTok{,}

  \DataTypeTok{type}\OperatorTok{:} \StringTok{'output'}\OperatorTok{,}

  \DataTypeTok{factory}\OperatorTok{:} \KeywordTok{function}\NormalTok{(el}\OperatorTok{,}\NormalTok{ width}\OperatorTok{,}\NormalTok{ height) }\OperatorTok{\{}

    \CommentTok{// }\AlertTok{TODO}\CommentTok{: define shared variables for this instance}
    \KeywordTok{var}\NormalTok{ controller}\OperatorTok{;}

    \ControlFlowTok{return} \OperatorTok{\{}

      \DataTypeTok{renderValue}\OperatorTok{:} \KeywordTok{function}\NormalTok{(x) }\OperatorTok{\{}

\NormalTok{        controller }\OperatorTok{=} \KeywordTok{new} \VariableTok{GIO}\NormalTok{.}\AttributeTok{Controller}\NormalTok{(el)}\OperatorTok{;} \CommentTok{// declared outside}
        
        \CommentTok{// add data}
        \VariableTok{controller}\NormalTok{.}\AttributeTok{addData}\NormalTok{(}\VariableTok{x}\NormalTok{.}\AttributeTok{data}\NormalTok{)}\OperatorTok{;}

        \CommentTok{// define style}
        \VariableTok{controller}\NormalTok{.}\AttributeTok{setStyle}\NormalTok{(}\VariableTok{x}\NormalTok{.}\AttributeTok{style}\NormalTok{)}\OperatorTok{;}

        \CommentTok{// render}
        \VariableTok{controller}\NormalTok{.}\AttributeTok{init}\NormalTok{()}\OperatorTok{;}

      \OperatorTok{\},}

      \DataTypeTok{resize}\OperatorTok{:} \KeywordTok{function}\NormalTok{(width}\OperatorTok{,}\NormalTok{ height) }\OperatorTok{\{}

        \CommentTok{// }\AlertTok{TODO}\CommentTok{: code to re-render the widget with a new size}

      \OperatorTok{\}}

    \OperatorTok{\};}
  \OperatorTok{\}}
\OperatorTok{\}}\NormalTok{)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

\hypertarget{widgets-adv-sizing}{%
\subsection{Sizing}\label{widgets-adv-sizing}}

The \texttt{gio} function of the package we developed in the previous chapter has arguments to specify the dimensions of the visualisation (width and height). However, think how rarely (if ever) one specifies these parameters when using plotly, highcharter, or leaflet. Indeed HTML visualisations should be responsive and fit the container they are placed in---not to be confused though; these are two different things. This enables creating visualisations that look great on large desktop screens as well as the smaller mobile phones or iPad screens. Pre-defining the dimensions of the visualisation\index{visualisation} (e.g.: \texttt{400px}), breaks all responsiveness as the width is no longer relative to its container. Using a relative width like \texttt{100\%} ensures the visualisation always fits in the container edge to edge and enables responsiveness.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{arcs <-}\StringTok{ }\NormalTok{jsonlite}\OperatorTok{::}\KeywordTok{fromJSON}\NormalTok{(}
  \StringTok{'[}
\StringTok{    \{}
\StringTok{      "e": "CN",}
\StringTok{      "i": "US",}
\StringTok{      "v": 3300000}
\StringTok{    \},}
\StringTok{    \{}
\StringTok{      "e": "CN",}
\StringTok{      "i": "RU",}
\StringTok{      "v": 10000}
\StringTok{    \}}
\StringTok{  ]'}
\NormalTok{)}

\KeywordTok{gio}\NormalTok{(arcs)}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/gio-size-issue} 

}

\caption{Gio with no sizing management}\label{fig:gio-size-issue}
\end{figure}

When this is not specified, htmlwidgets sets the width of the visualisation to 400 pixels (see Figure \ref{fig:gio-size-issue}).

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{gio}\NormalTok{(arcs, }\DataTypeTok{width =} \DecValTok{500}\NormalTok{) }\CommentTok{# 500 pixels wide}
\KeywordTok{gio}\NormalTok{(arcs, }\DataTypeTok{width =} \StringTok{"100%"}\NormalTok{) }\CommentTok{# fits width}
\end{Highlighting}
\end{Shaded}

These options are destined for the user of the package; the next section details how the developer can define default sizing behaviour.

\hypertarget{widgets-adv-sizing-policy}{%
\subsection{Sizing Policy}\label{widgets-adv-sizing-policy}}

One can specify a sizing policy when creating the widget, the sizing policy will dictate default dimensions and padding in different contexts:

\begin{itemize}
\tightlist
\item
  Global defaults
\item
  RStudio viewer\index{RStudio}
\item
  Web browser\index{web browser}
\item
  R markdown\index{R markdown}
\end{itemize}

It is often enough to specify general defaults as widgets are rarely expected to behave differently with respect to size depending on the context, but it can be useful in some cases.

Below we modify the sizing policy of gio via the \texttt{sizingPolicy} argument of the \texttt{createWidget} function. The function \texttt{htmlwidgets::sizingPolicy} has many arguments; we set the default width to 100\% to ensure the visualisation fills its container entirely regardless of where it is rendered. We also remove all padding by setting it to 0 and set \texttt{browser.fill} to \texttt{TRUE}, so it automatically resizes\index{resize} the visualisation to fit the entire browser page.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# create widget}
\NormalTok{htmlwidgets}\OperatorTok{::}\KeywordTok{createWidget}\NormalTok{(}
  \DataTypeTok{name =} \StringTok{'gio'}\NormalTok{,}
\NormalTok{  x,}
  \DataTypeTok{width =}\NormalTok{ width,}
  \DataTypeTok{height =}\NormalTok{ height,}
  \DataTypeTok{package =} \StringTok{'gio'}\NormalTok{,}
  \DataTypeTok{elementId =}\NormalTok{ elementId,}
  \DataTypeTok{sizingPolicy =}\NormalTok{ htmlwidgets}\OperatorTok{::}\KeywordTok{sizingPolicy}\NormalTok{(}
    \DataTypeTok{defaultWidth =} \StringTok{"100%"}\NormalTok{,}
    \DataTypeTok{padding =} \DecValTok{0}\NormalTok{,}
    \DataTypeTok{browser.fill =} \OtherTok{TRUE}
\NormalTok{  )}
\NormalTok{)}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/gio-fit} 

}

\caption{Gio with sizing policy}\label{fig:gio-fit}
\end{figure}

Figure \ref{fig:gio-fit} shows the modified \texttt{sizingPolicy} produces a visualisation that fills the browser.

\hypertarget{widgets-adv-resizing}{%
\section{Resizing}\label{widgets-adv-resizing}}

In the first widget built in this book (\texttt{playground}), we deconstructed the JavaScript \texttt{factory} function but omitted the \texttt{resize} function. The \texttt{resize} function does what it says on the tin: it is called when the widget is resized. What this function will contain entirely depends on the JavaScript library one is working with. Some are very easy to resize, other less so, that is for the developer to discover in the documentation of the library. Some libraries, like gio, do not even require using a resizing (see \ref{fig:gio-small}) function and handle that automatically under the hood; resize the width of the RStudio viewer or web browser\index{web browser}, and gio.js resizes too. This said, there is a function to force gio to resize\index{resize}. Though it is not in the official documentation, it can be found in the source code: \texttt{resizeUpdate} is a method of the controller and does not take any argument.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{...}
\NormalTok{resize}\OperatorTok{:} \KeywordTok{function}\NormalTok{(width}\OperatorTok{,}\NormalTok{ height) }\OperatorTok{\{}
  \VariableTok{controller}\NormalTok{.}\AttributeTok{resizeUpdate}\NormalTok{()}\OperatorTok{;}
\OperatorTok{\}}
\NormalTok{...}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/gio-small} 

}

\caption{Gio resized}\label{fig:gio-small}
\end{figure}

To give the reader a better idea of what these tend to look like below are the ways plotly, highcharts, and chart.js do it.

\textbf{Plotly}

\begin{Shaded}
\begin{Highlighting}[]
\VariableTok{Plotly}\NormalTok{.}\AttributeTok{relayout}\NormalTok{(}\StringTok{'chartid'}\OperatorTok{,} \OperatorTok{\{}\DataTypeTok{width}\OperatorTok{:}\NormalTok{ width}\OperatorTok{,} \DataTypeTok{height}\OperatorTok{:}\NormalTok{ height}\OperatorTok{\}}\NormalTok{)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

\textbf{Highcharts}

\begin{Shaded}
\begin{Highlighting}[]
\VariableTok{chart}\NormalTok{.}\AttributeTok{setSize}\NormalTok{(width}\OperatorTok{,}\NormalTok{ height)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

\textbf{Chart.js}

\begin{Shaded}
\begin{Highlighting}[]
\VariableTok{chart}\NormalTok{.}\AttributeTok{resize}\NormalTok{()}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

Note that the \texttt{width} and \texttt{height} used in the functions above are obtained from the \texttt{resize} function itself (see arguments).

That is one of the reasons for ensuring the instance of the visualisation (\texttt{controller} in this case) is shared (declared in \texttt{factory}). If declared in the \texttt{renderValue} function then the \texttt{resize} function cannot access that object and thus cannot run the function required to resize the widget.

\hypertarget{widgets-adv-prerender}{%
\section{Pre Render Hooks and Security}\label{widgets-adv-prerender}}

The \texttt{createWidget} function also comes with a \texttt{preRenderHook} argument, which accepts a function that is run just before the rendering of the widget (in R, not JavaScript), this function should accept the entire widget object as input and should return a modified widget object. That was not used in any of the widgets previously built but is extremely useful. It can be used to make checks on the object to ensure all is correct, or remove variables that should only be used internally, and much more.

Currently, \texttt{gio} takes the data frame \texttt{data} and serialises\index{serialise} it in its entirety which will cause security concerns as all the data used in the widget is visible in the source code of the output. What if the data used for the visualisation contained an additional column with sensitive information? We ought to ensure gio only serialises\index{serialise} the data necessary to produce the visualisation.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# add a variable that should not be shared}
\NormalTok{arcs}\OperatorTok{$}\NormalTok{secret_id <-}\StringTok{ }\DecValTok{1}\OperatorTok{:}\DecValTok{2}
\end{Highlighting}
\end{Shaded}

We create a \texttt{render\_gio} function, which accepts the entire widget, filters only the column necessary from the data and returns the widget. This function is then passed to the argument \texttt{preRenderHook} of the \texttt{htmlwidgets::createWidget} call. This way, only the columns \texttt{e}, \texttt{v}, and \texttt{i} of the data are kept, thus the \texttt{secret\_id} column will not be exposed publicly.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# preRenderHook function}
\NormalTok{render_gio <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(g)\{}
  \CommentTok{# only keep relevant variables}
\NormalTok{  g}\OperatorTok{$}\NormalTok{x}\OperatorTok{$}\NormalTok{data <-}\StringTok{ }\NormalTok{g}\OperatorTok{$}\NormalTok{x}\OperatorTok{$}\NormalTok{data[,}\KeywordTok{c}\NormalTok{(}\StringTok{"e"}\NormalTok{, }\StringTok{"v"}\NormalTok{, }\StringTok{"i"}\NormalTok{)]}
  \KeywordTok{return}\NormalTok{(g)}
\NormalTok{\}}

\CommentTok{# create widget}
\NormalTok{htmlwidgets}\OperatorTok{::}\KeywordTok{createWidget}\NormalTok{(}
  \DataTypeTok{name =} \StringTok{'gio'}\NormalTok{,}
\NormalTok{  x,}
  \DataTypeTok{width =}\NormalTok{ width,}
  \DataTypeTok{height =}\NormalTok{ height,}
  \DataTypeTok{package =} \StringTok{'gio'}\NormalTok{,}
  \DataTypeTok{elementId =}\NormalTok{ elementId,}
  \DataTypeTok{sizingPolicy =}\NormalTok{ htmlwidgets}\OperatorTok{::}\KeywordTok{sizingPolicy}\NormalTok{(}
    \DataTypeTok{defaultWidth =} \StringTok{"100%"}\NormalTok{,}
    \DataTypeTok{padding =} \DecValTok{0}\NormalTok{,}
    \DataTypeTok{browser.fill =} \OtherTok{TRUE}
\NormalTok{  ),}
  \DataTypeTok{preRenderHook =}\NormalTok{ render_gio }\CommentTok{# pass renderer}
\NormalTok{)}
\end{Highlighting}
\end{Shaded}

Moreover, security aside, this can also improve performances as only the data relevant to the visualisation is serialised\index{serialise} and subsequently loaded by the client. Without the modification above, were one to use \texttt{gio} on a dataset with 100 columns all would have been serialised\index{serialise}, thereby significantly impacting performances both of the R process rendering the output and the web browser\index{web browser} viewing the visualisation.

\hypertarget{widgets-adv-js}{%
\section{JavaScript Code}\label{widgets-adv-js}}

As mentioned in a previous chapter, JavaScript code cannot be serialised to JSON\index{JSON}.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# serialised as string}
\NormalTok{jsonlite}\OperatorTok{::}\KeywordTok{toJSON}\NormalTok{(}\StringTok{"var x = 3;"}\NormalTok{)}
\CommentTok{#> ["var x = 3;"]}
\end{Highlighting}
\end{Shaded}

Nonetheless, it is doable with htmlwidgets' serialiser\index{serialise} (and only that one). The function \texttt{htmlwidgets::JS} can be used to mark a character vector so that it will be treated as JavaScript code when evaluated in the browser.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{htmlwidgets}\OperatorTok{::}\KeywordTok{JS}\NormalTok{(}\StringTok{"var x = 3;"}\NormalTok{)  }
\CommentTok{#> [1] "var x = 3;"}
\CommentTok{#> attr(,"class")}
\CommentTok{#> [1] "JS_EVAL"}
\end{Highlighting}
\end{Shaded}

This can be useful where the library requires the use of callback functions, for instance.

\begin{rmdnote}
Replacing the serialiser\index{serialise} will break this feature.
\end{rmdnote}

\hypertarget{widgets-adv-prepend-append}{%
\section{Prepend and Append Content}\label{widgets-adv-prepend-append}}

There is the ability to append or prepend HTML content to the widget (Shiny\index{Shiny}, htmltools tags, or a list of those). For instance, we could use \texttt{htmlwidgets::prependContent} to allow displaying a title to the visualisation, as shown in Figure \ref{fig:gio-title}.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{#' @export}
\NormalTok{gio_title <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(g, title)\{}
\NormalTok{  title <-}\StringTok{ }\NormalTok{htmltools}\OperatorTok{::}\KeywordTok{h3}\NormalTok{(title)}
\NormalTok{  htmlwidgets}\OperatorTok{::}\KeywordTok{prependContent}\NormalTok{(g, title)}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{gio}\NormalTok{(arcs) }\OperatorTok{%>%}\StringTok{ }
\StringTok{  }\KeywordTok{gio_title}\NormalTok{(}\StringTok{"Gio.js htmlwidget!"}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/gio-title} 

}

\caption{Gio output with title}\label{fig:gio-title}
\end{figure}

While the \texttt{prependContent} function places the content above the visualisation, the \texttt{appendContent} function places it below, as they accept any valid htmltools or Shiny tag they can also be used for conditional CSS styling for instance.

\begin{rmdnote}
\texttt{prependContent} and \texttt{appendContent} do not work in Shiny.
\end{rmdnote}

\hypertarget{widgets-adv-dependencies}{%
\section{Dependencies}\label{widgets-adv-dependencies}}

Thus far, this book has only covered one of two ways dependencies can be included in htmlwidgets. Though the one covered, using the \texttt{.yml} file will likely be necessary for every widget it has one drawback: all dependencies\index{dependency} listed in the file are always included with the output. Dependencies can significantly affect the load time of the output (be it a standalone visualisation, an R markdown\index{R markdown} document, or a Shiny\index{Shiny} application) as these files may be large. Most large visualisation libraries will therefore allow bundling those dependencies in separate files. For instance, ECharts.js provides a way to customise the bundle to only include dependencies for charts that one wants to draw (e.g., bar chart, or boxplot), highcharts also allows splitting dependencies so one can load those needed for maps, stock charts, and more, separately. It is thus good practice to do the same in widgets, so only the required dependencies are loaded, e.g.: when the user produces a map, only the dependency\index{dependency} for that map is loaded. It is used in the leaflet package to load map tiles, for instance.

The Google Chrome network tab (see Figure \ref{fig:htmlwidgets-performances}) shows the information on resources downloaded by the browser (including dependencies) including how long it takes. It is advisable to take a look at it to ensure no dependency\index{dependency} drags load time.

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/htmlwidgets-performances} 

}

\caption{Google Chrome network tab}\label{fig:htmlwidgets-performances}
\end{figure}

To demonstrate, we will add a function in gio to optionally include \href{https://github.com/mrdoob/stats.js/}{stats.js}, a JavaScript performance monitor which displays information such as the number of frames per second (FPS) rendered, or the number of milliseconds needed to render the visualisation\index{visualisation}. Gio.js natively supports stats.js, but the dependency\index{dependency} needs to be imported, and that option needs to be enabled on the \texttt{controller} as shown in the \href{https://giojs.org/html/docs/interfaceStats.html}{documentation}.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{// enable stats}
\VariableTok{controller}\NormalTok{.}\AttributeTok{enableStats}\NormalTok{()}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

In htmlwidgets those additional dependencies\index{dependency} can be specified via the \texttt{dependencies} argument in the \texttt{htmlwidgets::createWidget} function or they can be appended to the output of that function.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# create gio object}
\NormalTok{g <-}\StringTok{ }\NormalTok{gio}\OperatorTok{::}\KeywordTok{gio}\NormalTok{(arcs)}

\KeywordTok{is.null}\NormalTok{(g}\OperatorTok{$}\NormalTok{dependencies)}
\end{Highlighting}
\end{Shaded}

\begin{verbatim}
[1] TRUE
\end{verbatim}

As shown above, the object created by \texttt{gio} includes dependencies, currently \texttt{NULL} as no such extra dependency\index{dependency} is specified. One can therefore append those to that object in a fashion similar to what the \texttt{gio\_style} function does.

From the root of the gio package, we create a new directory for the stats.js dependency and download the latest version from GitHub.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{dir.create}\NormalTok{(}\StringTok{"htmlwidgets/stats"}\NormalTok{)}
\NormalTok{url <-}\StringTok{ }\KeywordTok{paste0}\NormalTok{(}
  \StringTok{"https://raw.githubusercontent.com/mrdoob/"}\NormalTok{,}
  \StringTok{"stats.js/master/build/stats.min.js"}
\NormalTok{)}
\KeywordTok{download.file}\NormalTok{(url, }\DataTypeTok{destfile =} \StringTok{"htmlwidgets/stats/stats.min.js"}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

First we use the \texttt{system.file} function to retrieve \emph{the path to the directory} contains the dependency\index{dependency} (\texttt{stats.min.js}). It's important that it is the path to the directory and not the file itself.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# stats.R}
\NormalTok{gio_stats <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(g)\{}

  \CommentTok{# create dependency}
\NormalTok{  path <-}\StringTok{ }\KeywordTok{system.file}\NormalTok{(}\StringTok{"htmlwidgets/stats"}\NormalTok{, }\DataTypeTok{package =} \StringTok{"gio"}\NormalTok{)}

  \KeywordTok{return}\NormalTok{(g)}

\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

Then we use the htmltools package to create a dependency\index{dependency}, the \texttt{htmltools::htmlDependency} function returns an object of class \texttt{html\_dependency}, which htmlwidgets can understand and subsequently insert in the output. On the \texttt{src} parameter, since we reference a dependency from the filesystem we name the character string \texttt{file}, but we could use the CDN\index{CDN} (web-hosted file) and name it \texttt{href} instead.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# stats.R}
\NormalTok{gio_stats <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(g)\{}

  \CommentTok{# create dependency}
\NormalTok{  path <-}\StringTok{ }\KeywordTok{system.file}\NormalTok{(}\StringTok{"htmlwidgets/stats"}\NormalTok{, }\DataTypeTok{package =} \StringTok{"gio"}\NormalTok{)}
\NormalTok{  dep <-}\StringTok{ }\NormalTok{htmltools}\OperatorTok{::}\KeywordTok{htmlDependency}\NormalTok{(}
    \DataTypeTok{name =} \StringTok{"stats"}\NormalTok{,}
    \DataTypeTok{version =} \StringTok{"17"}\NormalTok{,}
    \DataTypeTok{src =} \KeywordTok{c}\NormalTok{(}\DataTypeTok{file =}\NormalTok{ path),}
    \DataTypeTok{script =} \StringTok{"stats.min.js"}
\NormalTok{  )}

  \KeywordTok{return}\NormalTok{(g)}

\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

The dependency\index{dependency} then needs to be appended to the htmlwidgets object.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# stats.R}
\NormalTok{gio_stats <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(g)\{}

  \CommentTok{# create dependency}
\NormalTok{  path <-}\StringTok{ }\KeywordTok{system.file}\NormalTok{(}\StringTok{"htmlwidgets/stats"}\NormalTok{, }\DataTypeTok{package =} \StringTok{"gio"}\NormalTok{)}
\NormalTok{  dep <-}\StringTok{ }\NormalTok{htmltools}\OperatorTok{::}\KeywordTok{htmlDependency}\NormalTok{(}
    \DataTypeTok{name =} \StringTok{"stats"}\NormalTok{,}
    \DataTypeTok{version =} \StringTok{"17"}\NormalTok{,}
    \DataTypeTok{src =} \KeywordTok{c}\NormalTok{(}\DataTypeTok{file =}\NormalTok{ path),}
    \DataTypeTok{script =} \StringTok{"stats.min.js"}
\NormalTok{  )}

  \CommentTok{# append dependency}
\NormalTok{  g}\OperatorTok{$}\NormalTok{dependencies <-}\StringTok{ }\KeywordTok{append}\NormalTok{(g}\OperatorTok{$}\NormalTok{dependencies, }\KeywordTok{list}\NormalTok{(dep))}

  \KeywordTok{return}\NormalTok{(g)}

\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

Finally, we pass an additional variable in the list of options (\texttt{x}), which we will use JavaScript-side to check whether stats.js must be enabled.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{#' @export}
\NormalTok{gio_stats <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(g)\{}

  \CommentTok{# create dependency}
\NormalTok{  path <-}\StringTok{ }\KeywordTok{system.file}\NormalTok{(}\StringTok{"htmlwidgets/stats"}\NormalTok{, }\DataTypeTok{package =} \StringTok{"gio"}\NormalTok{)}
\NormalTok{  dep <-}\StringTok{ }\NormalTok{htmltools}\OperatorTok{::}\KeywordTok{htmlDependency}\NormalTok{(}
    \DataTypeTok{name =} \StringTok{"stats"}\NormalTok{,}
    \DataTypeTok{version =} \StringTok{"17"}\NormalTok{,}
    \DataTypeTok{src =} \KeywordTok{c}\NormalTok{(}\DataTypeTok{file =}\NormalTok{ path),}
    \DataTypeTok{script =} \StringTok{"stats.min.js"}
\NormalTok{  )}

  \CommentTok{# append dependency to gio.js}
\NormalTok{  g}\OperatorTok{$}\NormalTok{dependencies <-}\StringTok{ }\KeywordTok{append}\NormalTok{(g}\OperatorTok{$}\NormalTok{dependencies, }\KeywordTok{list}\NormalTok{(dep))}

  \CommentTok{# add stats variable}
\NormalTok{  g}\OperatorTok{$}\NormalTok{x}\OperatorTok{$}\NormalTok{stats <-}\StringTok{ }\OtherTok{TRUE}

  \KeywordTok{return}\NormalTok{(g)}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

Then it is a matter of using the \texttt{stats} variable added to \texttt{x} in the JavaScript \texttt{renderValue} function to determine whether the stats feature should be enabled.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{// gio.js}
\ControlFlowTok{if}\NormalTok{(}\VariableTok{x}\NormalTok{.}\AttributeTok{stats}\NormalTok{)}
  \VariableTok{controller}\NormalTok{.}\AttributeTok{enableStats}\NormalTok{()}\OperatorTok{;}

\VariableTok{controller}\NormalTok{.}\AttributeTok{init}\NormalTok{()}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

Then the package can be documented to export\index{export} the newly-created function and loaded in the environment\index{environment} to test the feature, as shown in FIgure \ref{fig:gio-stats}.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# create gio object}
\NormalTok{arcs }\OperatorTok{%>%}\StringTok{ }
\StringTok{  }\KeywordTok{gio}\NormalTok{() }\OperatorTok{%>%}\StringTok{ }
\StringTok{  }\KeywordTok{gio_stats}\NormalTok{()}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/stats} 

}

\caption{Gio with stats output}\label{fig:gio-stats}
\end{figure}

In brief, it is better to only place the hard dependencies in the \texttt{.yml} file; dependencies\index{dependency} that are necessary to produce the visualisation and use dynamic dependencies where ever possible. Perhaps one can think of it as the difference between \texttt{Imports} and \texttt{Suggests} in an R package \texttt{DESCRIPTION} file.

\hypertarget{widgets-adv-compatibility}{%
\section{Compatibility}\label{widgets-adv-compatibility}}

One issue that might arise is that of compatibility between widgets. What if someone else builds another htmlwidget for gio.js uses a different version of the library and that a user decides to use both packages in a Shiny app or R markdown\index{R markdown} document? Something is likely to fail as two different versions of gio.js are imported, and that one overrides the other. For instance, the package echarts4r \citep{R-echarts4r} allows working with leaflet but including the dependencies\index{dependency} could clash with the leaflet package itself. Therefore, it uses the dependencies from the leaflet package instead.

The htmlwidgets package comes with a function to extract the dependencies\index{dependency} from a widget, so they can be reused in another. The function \texttt{htmlwidgets::getDependency} returns a list of objects of class \texttt{html\_dependency}, which can therefore be used in other widgets as demonstrated in the previous section.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# get dependencies of the gio package}
\NormalTok{htmlwidgets}\OperatorTok{::}\KeywordTok{getDependency}\NormalTok{(}\StringTok{"gio"}\NormalTok{)[}\DecValTok{2}\OperatorTok{:}\DecValTok{3}\NormalTok{]}
\end{Highlighting}
\end{Shaded}

\begin{verbatim}
#> [[1]]
#> List of 10
#>  $ name      : chr "three"
#>  $ version   : chr "110"
#>  $ src       :List of 1
#>   ..$ file: chr "/home/usr/gio/htmlwidgets/three"
#>  $ meta      : NULL
#>  $ script    : chr "three.min.js"
#>  $ stylesheet: NULL
#>  $ head      : NULL
#>  $ attachment: NULL
#>  $ package   : NULL
#>  $ all_files : logi TRUE
#>  - attr(*, "class")= chr "html_dependency"
#> 
#> [[2]]
#> List of 10
#>  $ name      : chr "gio"
#>  $ version   : chr "2"
#>  $ src       :List of 1
#>   ..$ file: chr "/home/usr/gio/htmlwidgets/gio"
#>  $ meta      : NULL
#>  $ script    : chr "gio.min.js"
#>  $ stylesheet: NULL
#>  $ head      : NULL
#>  $ attachment: NULL
#>  $ package   : NULL
#>  $ all_files : logi TRUE
#>  - attr(*, "class")= chr "html_dependency"
\end{verbatim}

\hypertarget{widgets-adv-unit-tests}{%
\section{Unit Tests}\label{widgets-adv-unit-tests}}

The best way to write unit tests for htmlwidgets is to test the object created by \texttt{htmlwidgets::createWidget}. We provide the following example using testthat \citep{R-testthat}, running \texttt{expect*} functions on the output of \texttt{gio}.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(gio)}
\KeywordTok{library}\NormalTok{(testthat)}

\KeywordTok{test_that}\NormalTok{(}\StringTok{"gio has correct data"}\NormalTok{, \{}
\NormalTok{  g <-}\StringTok{ }\KeywordTok{gio}\NormalTok{(arcs)}

  \CommentTok{# internally stored as data.frame}
  \KeywordTok{expect_is}\NormalTok{(g}\OperatorTok{$}\NormalTok{x}\OperatorTok{$}\NormalTok{data, }\StringTok{"data.frame"}\NormalTok{)}

  \CommentTok{# gio does not work without data}
  \KeywordTok{expect_error}\NormalTok{(}\KeywordTok{gio}\NormalTok{())}
\NormalTok{\})}
\end{Highlighting}
\end{Shaded}

\hypertarget{widgets-adv-performances}{%
\section{Performances}\label{widgets-adv-performances}}

A few hints have already been given to ensure one does not drain the browser; consider assessing the performances of the widget as it is being built. Always try and imagine what happens under the hood of the htmlwidget as you build it; it often reveals potential bottlenecks and solutions.

Remember that data passed to \texttt{htmlwidgets::createWidget} is 1) loaded into R, 2) serialised\index{serialise} to JSON\index{JSON}, 3) embedded into the HTML output, 4) read back in with JavaScript, which adds some overhead considering it might be read into JavaScript directly. This will not be a problem for most visualisations but might become one when that data is large. Indeed, there are sometimes more efficient ways to load data into web browsers\index{web browser} where it is needed for the visualisation.

Consider for instance, geographic features (topoJSON and GeoJSON), why load them into R if it is to then re-serialise it to JSON\index{JSON}?

Also, keep the previous remark in mind when repeatedly serialising identical data objects, GeoJSON is again a good example. A map used twice or more should only be serialised once or better not at all. Consider providing other ways for the developer to make potentially large data files accessible to the browser.

Below is an example of a function that could be used within R markdown\index{R markdown} or Shiny UI to load data in the front end and bypass serialisation. Additionally, the function makes use of AJAX (Asynchronous JavaScript And XML) to asynchronously load the data, thereby further reducing load time.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# this would placed in the shiny UI}
\NormalTok{load_json_from_ui <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(path_to_json)\{}
\NormalTok{  script <-}\StringTok{ }\KeywordTok{paste0}\NormalTok{(}\StringTok{"}
\StringTok{    $.ajax(\{ }
\StringTok{        url: '"}\NormalTok{, path_to_json, }\StringTok{"', }
\StringTok{        dataType: 'json', }
\StringTok{        async: true,}
\StringTok{        success: function(data)\{ }
\StringTok{          console.log(data);}
\StringTok{          window.globalData = data;}
\StringTok{        \} }
\StringTok{      \});"}
\NormalTok{    )}
\NormalTok{  shiny}\OperatorTok{::}\NormalTok{tags}\OperatorTok{$}\KeywordTok{script}\NormalTok{(}
\NormalTok{    script}
\NormalTok{  )}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

Using the above the data loaded would be accessible from the htmlwidgets JavaScript (e.g.: \texttt{gio.js}) with \texttt{window.globalData}. The \texttt{window} object is akin to the \texttt{document} object, while the latter pertains to the Document Object Model (DOM\index{DOM}) and represents the page, the former pertains to the Browser Object Model (BOM) and represents the browser window. While \texttt{var\ x;} will only be accessible within the script where it is declared, \texttt{window.x} will be accessible anywhere.

Note this means the data is read from the web browser\index{web browser}, and therefore the data must be accessible to the web browser; the \texttt{path\_to\_json} must thus be a served static file, e.g.: \texttt{www} directory in Shiny.

\hypertarget{linking-widgets}{%
\chapter{Linking Widgets}\label{linking-widgets}}

Widgets can be linked with one another using the crosstalk \citep{R-crosstalk} package, a fantastic add-on for htmlwidgets that implements inter-widget interactions, namely selection and filtering. This, in effect, allows the selection or filtering of data points in one widget to be mirrored in another. This is enabled with the creation of ``shared datasets'' that can be used across widgets: outputs that share datasets share interactions.

Crosstalk provides a straightforward interface to the users and instead requires effort from developers for their widgets to support shared datasets.

\hypertarget{linking-widgets-examples}{%
\section{Crosstalk Examples}\label{linking-widgets-examples}}

Both the plotly and DT packages support crosstalk, therefore using a shared dataset we can produce a scatter plot with the former and a table with the latter, so that selection of data in one is reflected in the other.

As alluded to earlier on, this can be achieved by using a shared dataset, which can be created with the \texttt{SharedData} R6 class from the crosstalk package. This dataset is then used as one would use a standard dataframe in plotly and DT. The \texttt{bscols} function is just a helper to create columns from HTML elements (see Figure \ref{fig:crosstalk-1}). It is ideal for examples, but one should not have to use it in Shiny\index{Shiny}---crosstalk will work without \texttt{bscols}.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(DT)}
\KeywordTok{library}\NormalTok{(plotly)}
\KeywordTok{library}\NormalTok{(crosstalk)}

\NormalTok{shared <-}\StringTok{ }\NormalTok{SharedData}\OperatorTok{$}\KeywordTok{new}\NormalTok{(cars)}

\KeywordTok{bscols}\NormalTok{(}
  \KeywordTok{plot_ly}\NormalTok{(shared, }\DataTypeTok{x =} \OperatorTok{~}\NormalTok{speed, }\DataTypeTok{y=}\OperatorTok{~}\NormalTok{dist),}
  \KeywordTok{datatable}\NormalTok{(shared, }\DataTypeTok{width =} \StringTok{"100%"}\NormalTok{)}
\NormalTok{)}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/crosstalk} 

}

\caption{Crosstalk example}\label{fig:crosstalk-1}
\end{figure}

Basic usage of crosstalk datasets in shiny (Figure \ref{fig:crosstalk-shiny}) is also straightforward since it accepts reactive expressions to create shared datasets. Note that it takes the expression itself (\texttt{expression}) not the output of the expression (\texttt{expression()}); the crosstalk documentation explains it best:

\begin{quote}
If this feels foreign to you, think of how you pass a function name, not a function call, to \texttt{lapply}; that's exactly analogous to what we're doing here.

\VA{--- Official crosstalk documentation}{}
\end{quote}

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(DT)}
\KeywordTok{library}\NormalTok{(shiny)}
\KeywordTok{library}\NormalTok{(plotly)}
\KeywordTok{library}\NormalTok{(crosstalk)}

\NormalTok{ui <-}\StringTok{ }\KeywordTok{fluidPage}\NormalTok{(}
  \KeywordTok{selectInput}\NormalTok{(}
    \StringTok{"specie"}\NormalTok{, }\StringTok{"Specie"}\NormalTok{, }
    \DataTypeTok{choices =} \KeywordTok{c}\NormalTok{(}\StringTok{"setosa"}\NormalTok{, }\StringTok{"versicolor"}\NormalTok{, }\StringTok{"virginica"}\NormalTok{)}
\NormalTok{  ),}
  \KeywordTok{fluidRow}\NormalTok{(}
    \KeywordTok{column}\NormalTok{(}\DecValTok{6}\NormalTok{, }\KeywordTok{DTOutput}\NormalTok{(}\StringTok{"table"}\NormalTok{)),}
    \KeywordTok{column}\NormalTok{(}\DecValTok{6}\NormalTok{, }\KeywordTok{plotlyOutput}\NormalTok{(}\StringTok{"plot"}\NormalTok{))}
\NormalTok{  )}
\NormalTok{)}

\NormalTok{server <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(input, output) \{}
\NormalTok{  reactive_data <-}\StringTok{ }\KeywordTok{reactive}\NormalTok{(\{}
\NormalTok{    iris[iris}\OperatorTok{$}\NormalTok{Species }\OperatorTok{==}\StringTok{ }\NormalTok{input}\OperatorTok{$}\NormalTok{specie, ]}
\NormalTok{  \})}

\NormalTok{  sd <-}\StringTok{ }\NormalTok{SharedData}\OperatorTok{$}\KeywordTok{new}\NormalTok{(reactive_data)}

\NormalTok{  output}\OperatorTok{$}\NormalTok{table <-}\StringTok{ }\KeywordTok{renderDT}\NormalTok{(\{}
    \KeywordTok{datatable}\NormalTok{(sd)}
\NormalTok{  \}, }\DataTypeTok{server =} \OtherTok{FALSE}\NormalTok{)}

\NormalTok{  output}\OperatorTok{$}\NormalTok{plot <-}\StringTok{ }\KeywordTok{renderPlotly}\NormalTok{(\{}
    \KeywordTok{plot_ly}\NormalTok{(sd, }\DataTypeTok{x =} \OperatorTok{~}\NormalTok{Sepal.Length, }\DataTypeTok{y =} \OperatorTok{~}\NormalTok{Sepal.Width)}
\NormalTok{  \})}
\NormalTok{\}}

\KeywordTok{shinyApp}\NormalTok{(ui, server)}
\end{Highlighting}
\end{Shaded}

\begin{rmdnote}
When working with shiny create the shared dataset in the server function
or some things that follow might not work as expected.
\end{rmdnote}

One can also use the \texttt{data} method on the crosstalk object in reactive expressions, which allows accessing the Javascript selection where crosstalk is not directly supported, like below in a custom UI block. Note that the argument \texttt{withSelection} is set to \texttt{TRUE} in order to retrieve the selection state of the rows.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(DT)}
\KeywordTok{library}\NormalTok{(shiny)}
\KeywordTok{library}\NormalTok{(crosstalk)}

\NormalTok{ui <-}\StringTok{ }\KeywordTok{fluidPage}\NormalTok{(}
  \KeywordTok{fluidRow}\NormalTok{(}
    \KeywordTok{column}\NormalTok{(}\DecValTok{4}\NormalTok{, }\KeywordTok{uiOutput}\NormalTok{(}\StringTok{"text"}\NormalTok{)),}
    \KeywordTok{column}\NormalTok{(}\DecValTok{8}\NormalTok{, }\KeywordTok{DTOutput}\NormalTok{(}\StringTok{"table"}\NormalTok{))}
\NormalTok{  )}
\NormalTok{)}

\NormalTok{server <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(input, output) \{}
\NormalTok{  sd <-}\StringTok{ }\NormalTok{SharedData}\OperatorTok{$}\KeywordTok{new}\NormalTok{(cars)}

\NormalTok{  output}\OperatorTok{$}\NormalTok{text <-}\StringTok{ }\KeywordTok{renderUI}\NormalTok{(\{}
    \CommentTok{# get selected rows}
\NormalTok{    n_selected <-}\StringTok{ }\NormalTok{sd}\OperatorTok{$}\KeywordTok{data}\NormalTok{(}\DataTypeTok{withSelection =} \OtherTok{TRUE}\NormalTok{) }\OperatorTok{%>%}\StringTok{ }
\StringTok{      }\NormalTok{dplyr}\OperatorTok{::}\KeywordTok{filter}\NormalTok{(selected_ }\OperatorTok{==}\StringTok{ }\OtherTok{TRUE}\NormalTok{) }\OperatorTok{%>%}\StringTok{ }
\StringTok{      }\KeywordTok{nrow}\NormalTok{()}

    \KeywordTok{h3}\NormalTok{(n_selected, }\StringTok{"selected items"}\NormalTok{)}
    
\NormalTok{  \})}

\NormalTok{  output}\OperatorTok{$}\NormalTok{table <-}\StringTok{ }\KeywordTok{renderDT}\NormalTok{(\{}
    \KeywordTok{datatable}\NormalTok{(sd)}
\NormalTok{  \}, }\DataTypeTok{server =} \OtherTok{FALSE}\NormalTok{)}
\NormalTok{\}}

\KeywordTok{shinyApp}\NormalTok{(ui, server)}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/crosstalk-shiny} 

}

\caption{Shiny with crosstalk}\label{fig:crosstalk-shiny}
\end{figure}

Using crosstalk with shiny one can also change the selection server-side with the \texttt{selection} method, passing it the keys to select.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(DT)}
\KeywordTok{library}\NormalTok{(shiny)}
\KeywordTok{library}\NormalTok{(crosstalk)}

\NormalTok{ui <-}\StringTok{ }\KeywordTok{fluidPage}\NormalTok{(}
  \KeywordTok{fluidRow}\NormalTok{(}
    \KeywordTok{column}\NormalTok{(}\DecValTok{4}\NormalTok{, }\KeywordTok{actionButton}\NormalTok{(}\StringTok{"random"}\NormalTok{, }\StringTok{"Select a random row"}\NormalTok{)),}
    \KeywordTok{column}\NormalTok{(}\DecValTok{8}\NormalTok{, }\KeywordTok{DTOutput}\NormalTok{(}\StringTok{"table"}\NormalTok{))}
\NormalTok{  )}
\NormalTok{)}

\NormalTok{server <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(input, output) \{}
\NormalTok{  sd <-}\StringTok{ }\NormalTok{SharedData}\OperatorTok{$}\KeywordTok{new}\NormalTok{(cars)}

\NormalTok{  output}\OperatorTok{$}\NormalTok{table <-}\StringTok{ }\KeywordTok{renderDT}\NormalTok{(\{}
    \KeywordTok{datatable}\NormalTok{(sd)}
\NormalTok{  \}, }\DataTypeTok{server =} \OtherTok{FALSE}\NormalTok{)}

\NormalTok{  selected <-}\StringTok{ }\KeywordTok{c}\NormalTok{()}
  \KeywordTok{observeEvent}\NormalTok{(input}\OperatorTok{$}\NormalTok{random, \{}
\NormalTok{    smp <-}\StringTok{ }\KeywordTok{c}\NormalTok{(}\DecValTok{1}\OperatorTok{:}\DecValTok{50}\NormalTok{)[}\OperatorTok{!}\DecValTok{1}\OperatorTok{:}\DecValTok{50} \OperatorTok{%in%}\StringTok{ }\NormalTok{selected]}
\NormalTok{    selected <<-}\StringTok{ }\KeywordTok{append}\NormalTok{(selected, }\KeywordTok{sample}\NormalTok{(smp, }\DecValTok{1}\NormalTok{))}
\NormalTok{    sd}\OperatorTok{$}\KeywordTok{selection}\NormalTok{(selected)}
\NormalTok{  \})}
\NormalTok{\}}

\KeywordTok{shinyApp}\NormalTok{(ui, server)}
\end{Highlighting}
\end{Shaded}

\hypertarget{linking-widgets-req}{%
\section{Crosstalk Requirements}\label{linking-widgets-req}}

Crosstalk will not work well with every widget and every dataset. In some cases, it might not even be a good idea to support it at all.

Crosstalk works best on rectangular data: dataframes or objects that resemble dataframes like \texttt{tibble} or \texttt{SpatialPolygonsDataFrame}. This is important as crosstalk will treat the data row-wise, where each row is an observation that is ultimately selected, or filtered. If the underlying data is not tabular (e.g.: trees), then one might eventually encounter mismatches between widgets as they go out of sync.

Other than tabular data, crosstalk will require the widget to have the necessary functions or methods to dispatch the selection and filtering that crosstalk enables; that is, the widget must be able to filter as well as highlight and fade selected data points as crosstalk itself does not provide this.

\hypertarget{linking-widgets-inner-workings}{%
\section{How it Works}\label{linking-widgets-inner-workings}}

As will be discovered later when support for crosstalk is brought to gio, minimal changes of the R code is required. As might be expected, crosstalk enables the communication between widgets via JavaScript. Hence much of what must be adapted by widgets developers happens in JavaScript too as shown in Figure \ref{fig:crosstalk-diagram}.

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/03-crosstalk-viz} 

}

\caption{Crosstalk visualised}\label{fig:crosstalk-diagram}
\end{figure}

Indeed the bi-directional communication between widgets works in the \index{RStudio} viewer, \index{R markdown}, Shiny, and elsewhere, clearly indicating that all of it is taking place in the browser.

\hypertarget{linking-widgets-keys}{%
\subsection{Keys}\label{linking-widgets-keys}}

This internally works with \texttt{key}s that are assigned to every row of the dataframe, which enable crosstalk to track which are selected or filtered.

When creating shared datasets crosstalk will by default use the row names of the data.frame, and if these are not available, the \texttt{SharedData} function will create row numbers.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{sd_cars <-}\StringTok{ }\NormalTok{SharedData}\OperatorTok{$}\KeywordTok{new}\NormalTok{(cars[}\DecValTok{1}\OperatorTok{:}\DecValTok{2}\NormalTok{,])}
\end{Highlighting}
\end{Shaded}

You can therefore \emph{mentally represent} the above-shared dataset as the following table. Note the emphasis; internally crosstalk does not actually add a column to the dataset: it leaves it as-is.

\begin{tabular}{l|r|r}
\hline
key & speed & dist\\
\hline
1 & 4 & 2\\
\hline
2 & 4 & 10\\
\hline
3 & 7 & 4\\
\hline
4 & 7 & 22\\
\hline
5 & 8 & 16\\
\hline
\end{tabular}

The keys assigned can be retrieve with the \texttt{key} method on the shared dataset itself.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{sd_cars}\OperatorTok{$}\KeywordTok{key}\NormalTok{()}
\CommentTok{#> [1] "1" "2"}
\end{Highlighting}
\end{Shaded}

Otherwise these keys can be explicitly set by the user when creating the package.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# assign keys}
\NormalTok{df <-}\StringTok{ }\KeywordTok{data.frame}\NormalTok{(}\DataTypeTok{x =} \KeywordTok{runif}\NormalTok{(}\DecValTok{5}\NormalTok{))}
\NormalTok{sd <-}\StringTok{ }\NormalTok{SharedData}\OperatorTok{$}\KeywordTok{new}\NormalTok{(df, }\DataTypeTok{key =}\NormalTok{ letters[}\DecValTok{1}\OperatorTok{:}\DecValTok{5}\NormalTok{])}
\NormalTok{sd}\OperatorTok{$}\KeywordTok{key}\NormalTok{()}
\CommentTok{#> [1] "a" "b" "c" "d" "e"}
\end{Highlighting}
\end{Shaded}

\hypertarget{linking-widgets-communication-lines}{%
\subsection{Communication Lines}\label{linking-widgets-communication-lines}}

In a sense, while crosstalk establishes lines of communication to transport \texttt{key}s between widgets, developers of the respective widgets must handle what \texttt{key}s are sent to other widgets and what to do with incoming \texttt{key}s (that are selected or filtered in other widgets). There are two such lines of communication, one for \texttt{key}s of rows to be filtered, meant to narrow down the selection of data points displayed on a widget, and another for selection (what crosstalk refers to as ``linked brushing'') to highlight specific data points (fading out other data points).

In JavaScript, a widget ``receives'' the keys of selected and filtered data points and must, when filtering or selection is observed, ``send'' said selected or filtered keys to other widgets.

\hypertarget{linking-widgets-groups}{%
\subsection{Groups}\label{linking-widgets-groups}}

Internally crosstalk knows what to share across widgets; with \texttt{group}s that share \texttt{key}s and are isolated from each other so one can use multiple different shared datasets without them interfering with each other (see Figure \ref{fig:crosstalk-groups-diagram}).

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/03-crosstalk-grps} 

}

\caption{Crosstalk groups visualised}\label{fig:crosstalk-groups-diagram}
\end{figure}

\begin{rmdnote}
Crosstalk groups share keys.
\end{rmdnote}

Therefore, the code below creates two shared datasets that are linked and share keys as they fall in the same \texttt{group} even though they are separate R objects.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{shared_cars <-}\StringTok{ }\NormalTok{SharedData}\OperatorTok{$}\KeywordTok{new}\NormalTok{(mtcars, }\DataTypeTok{group =} \StringTok{"cars"}\NormalTok{)}
\NormalTok{shared_cars_head <-}\StringTok{ }\NormalTok{SharedData}\OperatorTok{$}\KeywordTok{new}\NormalTok{(}\KeywordTok{head}\NormalTok{(mtcars), }\DataTypeTok{group =} \StringTok{"cars"}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

\hypertarget{linking-widgets-gio}{%
\section{Crosstalk with Gio}\label{linking-widgets-gio}}

The application of crosstalk to the gio library is somewhat amiss, but this makes it rather more instructive as it requires thinking beyond the mere implementation of the crosstalk and is an exercise the reader will likely have to do when incorporating it to other widgets. As mentioned before, in order for crosstalk to be properly implemented a widget must be able to select and deselect, as well as filter and unfilter data points, and this is not entirely the case of gio.

First, gio's underlying data is somewhat uncommon: it is a network defined only by its edges (the arcs leaving and coming into countries). Second, those edges themselves cannot be selected; as we've observed previously what edges are drawn on the globe cannot directly be defined; the selected country can be changed, which only by proxy changes the edges shown on the globe. Third, while gio supports changing which country is selected (by clicking on the globe), it does not allow unselecting a country; with gio.js a country is always selected.

The way crosstalk can work with gio is by setting the keys of the shared dataset to the country ISO codes that gio uses. Since data gio accepts consists of edges, this ISO code could correspond to either the source or the target country.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# keys = target}
\NormalTok{shared_arcs <-}\StringTok{ }\NormalTok{SharedData}\OperatorTok{$}\KeywordTok{new}\NormalTok{(arcs, }\DataTypeTok{key =}\NormalTok{ arcs}\OperatorTok{$}\NormalTok{e)}
\CommentTok{# keys = source}
\NormalTok{shared_arcs <-}\StringTok{ }\NormalTok{SharedData}\OperatorTok{$}\KeywordTok{new}\NormalTok{(arcs, }\DataTypeTok{key =}\NormalTok{ arcs}\OperatorTok{$}\NormalTok{i)}
\end{Highlighting}
\end{Shaded}

This constraint would have to be documented and communicated to the users of the package as otherwise, gio's implementation of crosstalk will not work.

Were the constraint of having to specify the keys removed, the gio package would have to interpret the keys. For instance, the widget would receive a selection, say \texttt{3} indicating that the third edge was selected in another widget; gio, not being able to highlight the edge, would have to decide whether to highlight either the country where the edge comes from or the country where the edge goes to. Though this could be implemented, it would be vastly more laborious and be more limited as the choice of country to highlight would no longer up to the user.

\hypertarget{linking-widgets-r}{%
\section{R code}\label{linking-widgets-r}}

In any event, let us start by making the required changes to the R code first. The only changes that need to be made are in the \texttt{gio} function as it is the only one that currently accepts a dataframe and thus may receive a shared dataset.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{class}\NormalTok{(shared_arcs)}
\CommentTok{#> [1] "SharedData" "R6"}
\end{Highlighting}
\end{Shaded}

Shared datasets are R6 classes and therefore cannot simply be treated as dataframes. The \texttt{gio} function needs to check whether the \texttt{data} object it received is a shared dataset with \texttt{is.SharedData} and, if so, use its methods to extract data from it, namely:

\begin{itemize}
\tightlist
\item
  The original dataset with \texttt{origData}
\item
  The group to which the dataset belongs with \texttt{groupName}
\item
  The keys that were assigned to every row of the dataset with \texttt{key}
\end{itemize}

The \texttt{origData} method is needed to extract the original dataframe from the shared dataset. That is, of course, necessary as the \texttt{gio} function still needs to obtain and serialise the arcs to display on the globe.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# original data}
\NormalTok{shared_arcs}\OperatorTok{$}\KeywordTok{origData}\NormalTok{()}
\CommentTok{#>    e  i       v}
\CommentTok{#> 1 CN US 3300000}
\CommentTok{#> 2 CN RU   10000}
\end{Highlighting}
\end{Shaded}

The \texttt{gio} function also has to extract the group to which the dataset belongs; this will be necessary on the JavaScript-side to tell crosstalk which group one is working with. Note that it was randomly generated since none were specified when the shared dataset was created.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# groupName}
\NormalTok{shared_arcs}\OperatorTok{$}\KeywordTok{groupName}\NormalTok{()}
\CommentTok{#> [1] "SharedDatadf3b988c"}

\CommentTok{# keys}
\NormalTok{shared_arcs}\OperatorTok{$}\KeywordTok{key}\NormalTok{()}
\CommentTok{#> [1] "US" "RU"}
\end{Highlighting}
\end{Shaded}

The methods \texttt{origData} and \texttt{groupName} must be used in every widget, the \texttt{key} method may not be of use to every widget, it can be immensely useful if the visualisation\index{visualisation} library also comes with a key/id system so one can use it internally. Gio.js does not, and we thus will not be using it. The name of the group is passed to the \texttt{x} object, so it is accessible JavaScript-side where it is needed; we also add the JavaScript dependency\index{dependency} required to run crosstalk with \texttt{crosstalkLibs}.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{gio <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(data, }\DataTypeTok{width =} \OtherTok{NULL}\NormalTok{, }\DataTypeTok{height =} \OtherTok{NULL}\NormalTok{, }
  \DataTypeTok{elementId =} \OtherTok{NULL}\NormalTok{) \{}

  \CommentTok{# defaults to NULL}
\NormalTok{  group <-}\StringTok{ }\OtherTok{NULL}
\NormalTok{  deps <-}\StringTok{ }\OtherTok{NULL}

  \CommentTok{# uses crosstalk}
  \ControlFlowTok{if}\NormalTok{ (crosstalk}\OperatorTok{::}\KeywordTok{is.SharedData}\NormalTok{(data)) \{}
\NormalTok{    group <-}\StringTok{ }\NormalTok{data}\OperatorTok{$}\KeywordTok{groupName}\NormalTok{()}
\NormalTok{    data <-}\StringTok{ }\NormalTok{data}\OperatorTok{$}\KeywordTok{origData}\NormalTok{()}
\NormalTok{    deps <-}\StringTok{ }\NormalTok{crosstalk}\OperatorTok{::}\KeywordTok{crosstalkLibs}\NormalTok{()}
\NormalTok{  \}}

  \CommentTok{# forward options using x}
\NormalTok{  x =}\StringTok{ }\KeywordTok{list}\NormalTok{(}
    \DataTypeTok{data =}\NormalTok{ data,}
    \DataTypeTok{style =} \StringTok{"default"}\NormalTok{,}
    \DataTypeTok{crosstalk =} \KeywordTok{list}\NormalTok{(}\DataTypeTok{group =}\NormalTok{ group) }\CommentTok{# pass group}
\NormalTok{  )}

  \KeywordTok{attr}\NormalTok{(x, }\StringTok{'TOJSON_ARGS'}\NormalTok{) <-}\StringTok{ }\KeywordTok{list}\NormalTok{(}\DataTypeTok{dataframe =} \StringTok{"rows"}\NormalTok{)}

  \CommentTok{# create widget}
\NormalTok{  htmlwidgets}\OperatorTok{::}\KeywordTok{createWidget}\NormalTok{(}
    \DataTypeTok{name =} \StringTok{'gio'}\NormalTok{,}
\NormalTok{    x,}
    \DataTypeTok{width =}\NormalTok{ width,}
    \DataTypeTok{height =}\NormalTok{ height,}
    \DataTypeTok{package =} \StringTok{'gio'}\NormalTok{,}
    \DataTypeTok{elementId =}\NormalTok{ elementId,}
    \DataTypeTok{sizingPolicy =}\NormalTok{ htmlwidgets}\OperatorTok{::}\KeywordTok{sizingPolicy}\NormalTok{(}
      \DataTypeTok{padding =} \DecValTok{0}\NormalTok{,}
      \DataTypeTok{browser.fill =} \OtherTok{TRUE}\NormalTok{,}
      \DataTypeTok{defaultWidth =} \StringTok{"100%"}
\NormalTok{    ),}
    \DataTypeTok{preRenderHook =}\NormalTok{ render_gio,}
    \CommentTok{# add crosstalk dependency}
    \DataTypeTok{dependencies =}\NormalTok{ deps}
\NormalTok{  )}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

\begin{rmdnote}
One could improve upon this section by using creating methods on the
\texttt{gio} function. It would make for cleaner code, but this is
outside the scope of this book.
\end{rmdnote}

\hypertarget{linking-widgets-js}{%
\section{JavaScript Code}\label{linking-widgets-js}}

What is left to do is to adapt the JavaScript code. As a reminder, it must accept the keys selected in other widgets and share the selected key with other widgets.

First, we create the selection handler in the \texttt{factory} function; this is done by instantiating a new class from \texttt{crosstalk.SelectionHandle}.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{var}\NormalTok{ sel_handle }\OperatorTok{=} \KeywordTok{new} \VariableTok{crosstalk}\NormalTok{.}\AttributeTok{SelectionHandle}\NormalTok{()}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

Once the selection handle created it can be used in the \texttt{renderValue} function to set the group that was collected from R.

\begin{Shaded}
\begin{Highlighting}[]
\VariableTok{sel_handle}\NormalTok{.}\AttributeTok{setGroup}\NormalTok{(}\VariableTok{x}\NormalTok{.}\VariableTok{crosstalk}\NormalTok{.}\AttributeTok{group}\NormalTok{)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

\hypertarget{linking-widgets-send-keys}{%
\subsection{Send Selected Keys}\label{linking-widgets-send-keys}}

In order for gio to share the selected country with other widgets, it would first have to know which country is selected. This can be achieved with a callback function that gio supports.

Most JavaScript visualisation libraries will support callbacks or events that are triggered when the user interacts with the visualisation so one can have arbitrary code run when, for example, a user clicks a point on a scatter plot, or when the user clicks the legend of a chart. What these callback functions will be and how they work will entirely depend on the library at hand.

In gio.js this callback function is fired when a country is selected on the globe, it accepts two objects: one containing data on the country selected and another containing data on the related countries (the arcs coming and leaving the selected country).

The \href{https://giojs.org/html/docs/callbackPicked.html}{documentation of gio.js} gives the following example callback function.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{// define callback function}
\KeywordTok{function} \AttributeTok{callback}\NormalTok{ (selectedCountry}\OperatorTok{,}\NormalTok{ relatedCountries) }\OperatorTok{\{}
  \VariableTok{console}\NormalTok{.}\AttributeTok{log}\NormalTok{(selectedCountry)}\OperatorTok{;}
  \CommentTok{// console.log(relatedCountries);}
\OperatorTok{\}}

\CommentTok{// use callback function}
\VariableTok{controller}\NormalTok{.}\AttributeTok{onCountryPicked}\NormalTok{(callback)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

\begin{Shaded}
\begin{Highlighting}[]
\FunctionTok{\{}\ErrorTok{name}\FunctionTok{:} \StringTok{"LIBYA"}\FunctionTok{,} \ErrorTok{lat}\FunctionTok{:} \DecValTok{25}\FunctionTok{,} \ErrorTok{lon}\FunctionTok{:} \DecValTok{17}\FunctionTok{,} \ErrorTok{center}\FunctionTok{:} \ErrorTok{n}\FunctionTok{,} \ErrorTok{ISOCode}\FunctionTok{:} \StringTok{"LY"}\FunctionTok{\}}
\end{Highlighting}
\end{Shaded}

This defines a function named \texttt{callback}, which takes the two objects as mentioned above and logs them in the JavaScript console. Then the function is passed to the \texttt{controller} via the \texttt{onCountryPicked} method, which will run it every time a country is selected by the user.

This callback function will be useful to send the \texttt{key}s to other widgets: when a user selects China to send the \texttt{CN} key selection via crosstalk.

As mentioned at the beginning of this section, the keys used with the datasets for gio.js should be country ISO codes. Therefore one can consider the variable \texttt{selectedCountry.ISOCode} as selected \texttt{key}. The \texttt{set} method from the selection handle can be used to share the selected key with other widgets. Note that this method expects either a \texttt{null} value or an array; a scalar value will throw an error, hence \texttt{selectedCountry.ISOCode} is wrapped in square brackets.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{function} \AttributeTok{callback}\NormalTok{ (selectedCountry) }\OperatorTok{\{}
  \VariableTok{sel_handle}\NormalTok{.}\AttributeTok{set}\NormalTok{([}\VariableTok{selectedCountry}\NormalTok{.}\AttributeTok{ISOCode}\NormalTok{])}\OperatorTok{;}
\OperatorTok{\}}

\VariableTok{controller}\NormalTok{.}\AttributeTok{onCountryPicked}\NormalTok{(callback)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

\hypertarget{linking-widgets-set-keys}{%
\subsection{Set Selected Keys}\label{linking-widgets-set-keys}}

We have implemented the necessary to share the selected country with other widgets but are yet to implement the opposite; when users select a country in another widget, the selected country in gio should change too. Gio does provide a method called \texttt{switchCountry} to change the selected country programmatically.

This can be achieved by listening to the \texttt{change} event on the selection handle previously created; below it is used to log the object \texttt{e} in order to inspect its properties.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{// placed in factory function}
\VariableTok{sel_handle}\NormalTok{.}\AttributeTok{on}\NormalTok{(}\StringTok{"change"}\OperatorTok{,} \KeywordTok{function}\NormalTok{(e) }\OperatorTok{\{}
  \VariableTok{console}\NormalTok{.}\AttributeTok{log}\NormalTok{(e)}\OperatorTok{;}
\OperatorTok{\}}\NormalTok{)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

\begin{Shaded}
\begin{Highlighting}[]
\FunctionTok{\{}
  \ErrorTok{oldValue}\FunctionTok{:} \OtherTok{[]}\FunctionTok{,}
  \ErrorTok{sender}\FunctionTok{:} \ErrorTok{n} \FunctionTok{\{}
    \ErrorTok{_eventRelay}\FunctionTok{:} \ErrorTok{e}\FunctionTok{,} 
    \ErrorTok{_emitter}\FunctionTok{:} \ErrorTok{t}\FunctionTok{,} 
    \ErrorTok{_group}\FunctionTok{:} \StringTok{"SharedDatac7682f87"}\FunctionTok{,} 
    \ErrorTok{_var}\FunctionTok{:} \ErrorTok{r}\FunctionTok{,} 
    \ErrorTok{_varOnChangeSub}\FunctionTok{:} \StringTok{"sub1"}\FunctionTok{,} 
    \ErrorTok{…}
  \FunctionTok{\},}
  \ErrorTok{value}\FunctionTok{:} \OtherTok{[}\StringTok{"AE"}\OtherTok{]}
\FunctionTok{\}}
\end{Highlighting}
\end{Shaded}

\begin{enumerate}
\def\labelenumi{\arabic{enumi}.}
\tightlist
\item
  \texttt{oldValue} - the value that was previously selected (if any); this may be useful if the widget wants to calculate differences between the currently and previously selected value.
\item
  \texttt{sender} - the selection handle instance that made the change. This is useful to compare against the selection handle of the widget and know whether this widget or another initiated the selection change. It is often used to clear the selection or filtering before applying a new one when the change comes from another widget.
\item
  \texttt{value} - the array of selected keys.
\end{enumerate}

Therefore event listener could make use of gio.js' \texttt{switchCountry}. Note that 1) the selection cannot be cleared with gio.js, a country is always selected, and 2) one can only select one country a time, hence only accepting the first element of the selected keys with \texttt{e.value{[}0{]}}.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{// placed in factory function}
\VariableTok{sel_handle}\NormalTok{.}\AttributeTok{on}\NormalTok{(}\StringTok{"change"}\OperatorTok{,} \KeywordTok{function}\NormalTok{(e) }\OperatorTok{\{}

  \CommentTok{// selection comes from another widget}
  \ControlFlowTok{if}\NormalTok{ (}\VariableTok{e}\NormalTok{.}\AttributeTok{sender} \OperatorTok{!==}\NormalTok{ sel_handle) }\OperatorTok{\{}
    \CommentTok{// clear the selection}
    \CommentTok{// not possible with gio.js}
  \OperatorTok{\}}
  \VariableTok{controller}\NormalTok{.}\AttributeTok{switchCountry}\NormalTok{(}\VariableTok{e}\NormalTok{.}\AttributeTok{value}\NormalTok{[}\DecValTok{0}\NormalTok{])}\OperatorTok{;}
\OperatorTok{\}}\NormalTok{)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

\hypertarget{linking-widgets-using}{%
\section{Using Crosstalk with Gio}\label{linking-widgets-using}}

Finally, now that gio supports shared datasets, we can create a few examples to demonstrate how it can be used.

The simplest way is probably to convert the edges to a shared dataset specifying either the source (\texttt{i}) or target (\texttt{e}) country codes as keys. However, this is unlikely to be used this way out in the real world. In Figure \ref{fig:crosstalk-gio-1}, selecting an edge highlights a node, which is somewhat confusing.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(DT)}
\KeywordTok{library}\NormalTok{(gio)}
\KeywordTok{library}\NormalTok{(crosstalk)}

\NormalTok{url <-}\StringTok{ }\KeywordTok{paste0}\NormalTok{(}
  \StringTok{"https://raw.githubusercontent.com/JohnCoene/"}\NormalTok{,}
  \StringTok{"javascript-for-r/master/data/countries.json"}
\NormalTok{)}
\NormalTok{arcs <-}\StringTok{ }\NormalTok{jsonlite}\OperatorTok{::}\KeywordTok{fromJSON}\NormalTok{(url)}

\CommentTok{# Wrap data frame in SharedData}
\CommentTok{# key is importing country}
\NormalTok{sd <-}\StringTok{ }\NormalTok{SharedData}\OperatorTok{$}\KeywordTok{new}\NormalTok{(arcs, }\DataTypeTok{key =}\NormalTok{ arcs}\OperatorTok{$}\NormalTok{i)}

\KeywordTok{bscols}\NormalTok{(}
  \KeywordTok{gio}\NormalTok{(sd),}
  \KeywordTok{datatable}\NormalTok{(sd, }\DataTypeTok{width=}\StringTok{"100%"}\NormalTok{, }\DataTypeTok{selection =} \StringTok{"single"}\NormalTok{)}
\NormalTok{)}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/crosstalk-gio-1} 

}

\caption{Gio with DT using crosstalk}\label{fig:crosstalk-gio-1}
\end{figure}

Thankfully we can use the \texttt{group} argument in order to create edges and nodes that share keys (see Figure \ref{fig:crosstalk-gio-diagram}) and produce a more sensible link between widgets.

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/03-crosstalk-gio} 

}

\caption{Crosstalk with gio}\label{fig:crosstalk-gio-diagram}
\end{figure}

Below we create two shared datasets with the same group name, one for the edges and another for the nodes to produce Figure \ref{fig:crosstalk-gio-2}. Use one for the gio visualisation and the other for the plotly graph.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(gio)}
\KeywordTok{library}\NormalTok{(plotly)}
\KeywordTok{library}\NormalTok{(crosstalk)}

\NormalTok{url <-}\StringTok{ }\KeywordTok{paste0}\NormalTok{(}
  \StringTok{"https://raw.githubusercontent.com/JohnCoene/"}\NormalTok{,}
  \StringTok{"javascript-for-r/master/data/countries.json"}
\NormalTok{)}
\NormalTok{arcs <-}\StringTok{ }\NormalTok{jsonlite}\OperatorTok{::}\KeywordTok{fromJSON}\NormalTok{(url)}

\CommentTok{# Wrap data frame in SharedData}
\NormalTok{edges_sd <-}\StringTok{ }\NormalTok{SharedData}\OperatorTok{$}\KeywordTok{new}\NormalTok{(}
\NormalTok{  arcs, }\DataTypeTok{key =}\NormalTok{ arcs}\OperatorTok{$}\NormalTok{i, }\DataTypeTok{group =} \StringTok{"sharedGroup"}
\NormalTok{)}

\CommentTok{# create nodes}
\NormalTok{iso2c <-}\StringTok{ }\KeywordTok{unique}\NormalTok{(arcs}\OperatorTok{$}\NormalTok{i)}
\NormalTok{nodes <-}\StringTok{ }\KeywordTok{data.frame}\NormalTok{(}
  \DataTypeTok{country =}\NormalTok{ iso2c,}
  \DataTypeTok{y =} \KeywordTok{rnorm}\NormalTok{(}\KeywordTok{length}\NormalTok{(iso2c))}
\NormalTok{)}
\NormalTok{nodes_sd <-}\StringTok{ }\NormalTok{SharedData}\OperatorTok{$}\KeywordTok{new}\NormalTok{(}
\NormalTok{  nodes, }\DataTypeTok{key =}\NormalTok{ nodes}\OperatorTok{$}\NormalTok{country, }
  \DataTypeTok{group =} \StringTok{"sharedGroup"}
\NormalTok{)}

\KeywordTok{bscols}\NormalTok{(}
  \KeywordTok{plot_ly}\NormalTok{(}\DataTypeTok{data =}\NormalTok{ nodes_sd, }\DataTypeTok{type =} \StringTok{"bar"}\NormalTok{, }\DataTypeTok{x =} \OperatorTok{~}\NormalTok{country, }\DataTypeTok{y =} \OperatorTok{~}\NormalTok{y) }\OperatorTok{%>%}\StringTok{ }
\StringTok{    }\KeywordTok{config}\NormalTok{(}\DataTypeTok{displayModeBar =} \OtherTok{FALSE}\NormalTok{),}
  \KeywordTok{gio}\NormalTok{(edges_sd)}
\NormalTok{)}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/crosstalk-gio-2} 

}

\caption{Gio and plotly using crosstalk and groups}\label{fig:crosstalk-gio-2}
\end{figure}

\hypertarget{widgets-final}{%
\chapter{Final Revisions}\label{widgets-final}}

In this chapter, we polish the API that gio presents its users and provide guidelines to integrate other JavaScript libraries with R best.

\hypertarget{widgets-final-data}{%
\section{Htmlwidgets and Data}\label{widgets-final-data}}

The gio package built thus far revolves around the \texttt{gio} function, which expects a dataframe with three columns named \texttt{e}, \texttt{i}, and \texttt{v}, which is not great practice; there are ample reasons why very few functions do that.

First, it is unlikely that one comes across a dataset with such names in the real world thus users of the package will likely need to rename the columns of the dataset in order to use gio, making the package rather unwieldy. Second, this makes understanding and approaching the gio package more complicated; it will not be evident by looking at the examples, and usage of gio.

Instead \texttt{gio} should accept the dataframe as the first argument and then the relevant columns to extract. This can be implemented in many ways ranging from arguments that accept the column names as strings to reproducing ggplot2's \texttt{aes} function. Here we settle for using non-standard evaluation to provide arguments that accept the bare name of the columns.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{gio <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(data, source, target, value, ..., }
  \DataTypeTok{width =} \OtherTok{NULL}\NormalTok{, }\DataTypeTok{height =} \OtherTok{NULL}\NormalTok{, }\DataTypeTok{elementId =} \OtherTok{NULL}\NormalTok{) \{}

  \CommentTok{# defaults to NULL}
\NormalTok{  group <-}\StringTok{ }\OtherTok{NULL}

  \ControlFlowTok{if}\NormalTok{ (crosstalk}\OperatorTok{::}\KeywordTok{is.SharedData}\NormalTok{(data)) \{}
\NormalTok{    group <-}\StringTok{ }\NormalTok{data}\OperatorTok{$}\KeywordTok{groupName}\NormalTok{()}
\NormalTok{    data <-}\StringTok{ }\NormalTok{data}\OperatorTok{$}\KeywordTok{origData}\NormalTok{()}
\NormalTok{  \}}

\NormalTok{  data <-}\StringTok{ }\NormalTok{dplyr}\OperatorTok{::}\KeywordTok{select}\NormalTok{(}
\NormalTok{    data,}
    \DataTypeTok{i =}\NormalTok{ \{\{ source \}\},}
    \DataTypeTok{e =}\NormalTok{ \{\{ target \}\},}
    \DataTypeTok{v =}\NormalTok{ \{\{ value \}\}}
\NormalTok{  )}

  \CommentTok{# forward options using x}
\NormalTok{  x =}\StringTok{ }\KeywordTok{list}\NormalTok{(}
    \DataTypeTok{configs =} \KeywordTok{list}\NormalTok{(...),}
    \DataTypeTok{data =}\NormalTok{ data,}
    \DataTypeTok{style =} \StringTok{"default"}\NormalTok{,}
    \DataTypeTok{crosstalk =} \KeywordTok{list}\NormalTok{(}\DataTypeTok{group =}\NormalTok{ group)}
\NormalTok{  )}

  \KeywordTok{attr}\NormalTok{(x, }\StringTok{'TOJSON_ARGS'}\NormalTok{) <-}\StringTok{ }\KeywordTok{list}\NormalTok{(}\DataTypeTok{dataframe =} \StringTok{"rows"}\NormalTok{)}

  \CommentTok{# create widget}
\NormalTok{  htmlwidgets}\OperatorTok{::}\KeywordTok{createWidget}\NormalTok{(}
    \DataTypeTok{name =} \StringTok{'gio'}\NormalTok{,}
\NormalTok{    x,}
    \DataTypeTok{width =}\NormalTok{ width,}
    \DataTypeTok{height =}\NormalTok{ height,}
    \DataTypeTok{package =} \StringTok{'gio'}\NormalTok{,}
    \DataTypeTok{elementId =}\NormalTok{ elementId,}
    \DataTypeTok{sizingPolicy =}\NormalTok{ htmlwidgets}\OperatorTok{::}\KeywordTok{sizingPolicy}\NormalTok{(}
      \DataTypeTok{padding =} \DecValTok{0}\NormalTok{,}
      \DataTypeTok{browser.fill =} \OtherTok{TRUE}\NormalTok{,}
      \DataTypeTok{defaultWidth =} \StringTok{"100%"}
\NormalTok{    ),}
    \DataTypeTok{preRenderHook =}\NormalTok{ render_gio,}
    \DataTypeTok{dependencies =}\NormalTok{ crosstalk}\OperatorTok{::}\KeywordTok{crosstalkLibs}\NormalTok{()}
\NormalTok{  )}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

The above changes allow documenting the input that \texttt{gio} accepts more clearly with roxygen2 and also makes its usage more transparent: it is now clear to users what data is required to create a visualisation, and they are free to use dataframes of their choice.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# mock up data}
\NormalTok{countries <-}\StringTok{ }\KeywordTok{c}\NormalTok{(}\StringTok{"US"}\NormalTok{, }\StringTok{"BE"}\NormalTok{, }\StringTok{"FR"}\NormalTok{, }\StringTok{"DE"}\NormalTok{)}
\NormalTok{df <-}\StringTok{ }\KeywordTok{data.frame}\NormalTok{(}
  \DataTypeTok{from =}\NormalTok{ countries,}
  \DataTypeTok{to =} \KeywordTok{rev}\NormalTok{(countries),}
  \DataTypeTok{traded =} \KeywordTok{runif}\NormalTok{(}\DecValTok{4}\NormalTok{)}
\NormalTok{)}

\CommentTok{# use gio}
\KeywordTok{gio}\NormalTok{(df, }\DataTypeTok{source =}\NormalTok{ from, }\DataTypeTok{target =}\NormalTok{ to, }\DataTypeTok{value =}\NormalTok{ traded)}
\end{Highlighting}
\end{Shaded}

This small change makes the package a great deal more comfortable to use and understand as \texttt{source}, and \texttt{target} are vastly more evident to understand than \texttt{e} and \texttt{i}.

\hypertarget{widgets-final-options}{%
\section{Plethora of Options}\label{widgets-final-options}}

Some JavaScript libraries can be extensive and come with thousands of options that can make the port to R rather bulky. Never hesitate to make use of the three dots construct (\texttt{...}) to make these accessible yet saving you from having to hard-code thousands of arguments.

For instance, gio.js accepts a JSON\index{JSON} of options to customise the globe further. One could port all of these manually, or allow users to specify those configurations via the three-dot construct.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{var}\NormalTok{ configs }\OperatorTok{=} \OperatorTok{\{}
  \DataTypeTok{control}\OperatorTok{:} \OperatorTok{\{}
    \DataTypeTok{stats}\OperatorTok{:} \KeywordTok{false}\OperatorTok{,}
    \DataTypeTok{disableUnmentioned}\OperatorTok{:} \KeywordTok{false}\OperatorTok{,}
    \DataTypeTok{lightenMentioned}\OperatorTok{:} \KeywordTok{false}\OperatorTok{,}
    \DataTypeTok{inOnly}\OperatorTok{:} \KeywordTok{false}\OperatorTok{,}
    \DataTypeTok{outOnly}\OperatorTok{:} \KeywordTok{false}\OperatorTok{,}
    \DataTypeTok{initCountry}\OperatorTok{:} \StringTok{"CN"}\OperatorTok{,}
    \DataTypeTok{halo}\OperatorTok{:} \KeywordTok{true}
  \OperatorTok{\},}
  \DataTypeTok{color}\OperatorTok{:} \OperatorTok{\{}
    \DataTypeTok{surface}\OperatorTok{:} \BaseNTok{0xFFFFFF}\OperatorTok{,}
    \DataTypeTok{selected}\OperatorTok{:} \KeywordTok{null}\OperatorTok{,}
    \KeywordTok{in}\OperatorTok{:} \BaseNTok{0x154492}\OperatorTok{,}
    \DataTypeTok{out}\OperatorTok{:} \BaseNTok{0xDD380C}\OperatorTok{,}
    \DataTypeTok{halo}\OperatorTok{:} \BaseNTok{0xFFFFFF}\OperatorTok{,}
    \DataTypeTok{background}\OperatorTok{:} \KeywordTok{null}
  \OperatorTok{\},}
  \DataTypeTok{brightness}\OperatorTok{:} \OperatorTok{\{}
    \DataTypeTok{ocean}\OperatorTok{:} \FloatTok{0.5}\OperatorTok{,}
    \DataTypeTok{mentioned}\OperatorTok{:} \FloatTok{0.5}\OperatorTok{,}
    \DataTypeTok{related}\OperatorTok{:} \FloatTok{0.5}
  \OperatorTok{\}}
\OperatorTok{\}}

\NormalTok{controller }\OperatorTok{=} \KeywordTok{new} \VariableTok{Gio}\NormalTok{.}\AttributeTok{controller}\NormalTok{(el}\OperatorTok{,}\NormalTok{ configs)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

The three dots can be added to the \texttt{gio} function, which internally captures them in a \texttt{list} named \texttt{configs} so it can be easily referenced in JavaScript.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# add ...three dots}
\NormalTok{gio <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(data, source, target, value, ..., }
  \DataTypeTok{width =} \OtherTok{NULL}\NormalTok{, }\DataTypeTok{height =} \OtherTok{NULL}\NormalTok{, }\DataTypeTok{elementId =} \OtherTok{NULL}\NormalTok{) \{}

  \CommentTok{# ... start of the function}

  \CommentTok{# forward options using x}
\NormalTok{  x =}\StringTok{ }\KeywordTok{list}\NormalTok{(}
    \DataTypeTok{configs =} \KeywordTok{list}\NormalTok{(...), }\CommentTok{# pass to configs}
    \DataTypeTok{data =}\NormalTok{ data,}
    \DataTypeTok{style =} \StringTok{"default"}\NormalTok{,}
    \DataTypeTok{crosstalk =} \KeywordTok{list}\NormalTok{(}\DataTypeTok{group =}\NormalTok{ group)}
\NormalTok{  )}

  \CommentTok{# ... end of the function}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

In JavaScript, use the \texttt{configs} when initialising the visualisation.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{// use x.configs}
\NormalTok{controller }\OperatorTok{=} \KeywordTok{new} \VariableTok{GIO}\NormalTok{.}\AttributeTok{Controller}\NormalTok{(el}\OperatorTok{,} \VariableTok{x}\NormalTok{.}\AttributeTok{configs}\NormalTok{)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

Below those configuration options are now used to set the initially selected country to the United States and change the colour of the selected country to red in Figure \ref{fig:crosstalk-three-dots}.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{gio}\NormalTok{(}
\NormalTok{  df, from, to, traded, }
  \DataTypeTok{control =} \KeywordTok{list}\NormalTok{(}\DataTypeTok{initCountry =} \StringTok{'US'}\NormalTok{), }
  \DataTypeTok{color =} \KeywordTok{list}\NormalTok{(}\DataTypeTok{selected =} \StringTok{'#ff4d4d'}\NormalTok{)}
\NormalTok{) }
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/crosstalk-three-dots} 

}

\caption{Gio and plenty of options}\label{fig:crosstalk-three-dots}
\end{figure}

\hypertarget{widgets-final-interface}{%
\section{Interface Design}\label{widgets-final-interface}}

As you develop a wrapper to an external visualisation library, you will have to make design choices. In building gio, we more or less mirrored the JavaScript code one to one: where there is a JavaScript function to change the theme of the visualisation, there is one in R, etc. This might not scale appropriately as more and more functions are added to the package.

As observed, the gio.js library has a function named \texttt{setStyle} to change the theme of the visualisation, but it has numerous others, \texttt{setSurfaceColor}, \texttt{addHalo}, \texttt{setHaloColor}, \texttt{removeHalo}, and plenty more. We might want to wrap all or some of these in a single function to provide a more convenient API to the R user.

\begin{rmdnote}
Design for humans: always keep in mind the interface you make available
to users as you develop the package.
\end{rmdnote}

You can always go beyond what the underlying library provides. For instance, the country selected by default is always China, regardless of whether the data includes that country or not. This can lead to creating underwhelming visualisations as no arcs appear. One can consider adding simple heiristics to the \texttt{gio} function to ensure that is not the case, or have the function throw a warning when the initial country is not present in the dataset.

Finally, consider R users' expectations. There are many prominent visualisation\index{visualisation} packages on CRAN\index{CRAN} already, users of the gio package will likely have used ggplot2 \citep{R-ggplot2}, plotly, or highcharter before. Though these provide somewhat different APIs, they set precedents. The more the API of gio resembles those, the easier it will be for new users to start using gio. However, do not let this restrict the package either. Never hesitate to do differently than ggplot2 if you think it will provide a better interface to your users.

\hypertarget{widgets-final-exercises}{%
\section{Exercises}\label{widgets-final-exercises}}

Widgets likely involve numerous concepts that are new to most readers. It is a good idea to try and work on a widget of your own to grasp the learnings of this part of the book entirely. A quick Google search for ``JavaScript visualisation libraries'' uncovers hundreds of candidate libraries that can be made accessible from R; below is but a small selection.

\begin{itemize}
\tightlist
\item
  \href{https://www.chartjs.org/}{chart.js} - simple yet flexible JavaScript charting
\item
  \href{https://js.cytoscape.org/}{cytoscape.js} - network theory library for visualisation and analysis
\item
  \href{https://ui.toast.com/tui-chart/}{Toast UI charts} - easy way to draw various and essential charts
\item
  \href{https://www.amcharts.com/}{amcharts} - library for all your data visualization needs
\end{itemize}

\hypertarget{part-web-development-with-shiny}{%
\part{Web Development with Shiny}\label{part-web-development-with-shiny}}

\hypertarget{shiny-intro}{%
\chapter{Bidirectional Communication}\label{shiny-intro}}

Shiny is the web framework of choice for the R programming language. Since JavaScript and Shiny both run in web browsers\index{web browser} it follows that they can run alongside one another as one can include JavaScript in such applications. However, often disregarded is the ability for Shiny's R server to communicate to the front end and vice versa. This collection of chapters aims to show precisely how this works. In this first part, we brush up on the essentials, so we understand how to include JavaScript in shiny applications.

Then again, the goal is not to write a lot of convoluted JavaScript. On the contrary, with little knowledge of the language the aim is to write as little as possible but demonstrate to the reader that it is often enough to vastly improve the user experience of Shiny applications.

\hypertarget{shiny-intro-websocket}{%
\section{WebSocket an Shiny}\label{shiny-intro-websocket}}

Shiny\index{Shiny} applications have two components: the user interface (UI) and the server function. These two components communicate via a WebSocket\index{WebSocket}: a persistent connection that allows passing messages between the server and clients connecting to it. In the R server, this connection is managed by Shiny using the httpuv \citep{R-httpuv} and WebSocket \citep{R-websocket} packages, while in clients connecting to the server this connection is managed with JavaScript, as depicted in \ref{fig:websocket-diag}.

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/04-websocket} 

}

\caption{Websocket visualised}\label{fig:websocket-diag}
\end{figure}

With that in mind, we can put together a Shiny application, which though simple. Exploits bi-directional communication. The application takes a text input, sends the value of the input to the R server, which sends it back to the UI.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(shiny)}

\NormalTok{ui <-}\StringTok{ }\KeywordTok{fluidPage}\NormalTok{(}
  \KeywordTok{textInput}\NormalTok{(}\StringTok{"nameInput"}\NormalTok{, }\StringTok{"Your name"}\NormalTok{),}
  \KeywordTok{textOutput}\NormalTok{(}\StringTok{"nameOutput"}\NormalTok{)}
\NormalTok{)}

\NormalTok{server <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(input, output) \{}
\NormalTok{  output}\OperatorTok{$}\NormalTok{nameOutput <-}\StringTok{ }\KeywordTok{renderText}\NormalTok{(\{}
\NormalTok{    input}\OperatorTok{$}\NormalTok{nameInput}
\NormalTok{  \})}
\NormalTok{\}}

\KeywordTok{shinyApp}\NormalTok{(ui, server)}
\end{Highlighting}
\end{Shaded}

Drawing a diagram of the communication between the UI and the server (Figure \ref{fig:shiny-websocket-diagram}) reveals that though this is a simple application a lot is happening.

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/04-shiny-websocket} 

}

\caption{Shiny websocket visualised}\label{fig:shiny-websocket-diagram}
\end{figure}

Communicating between the R server and the user interface requires JavaScript and thus makes a reasonable chunk of this part of the book on web development with Shiny.

\hypertarget{shiny-intro-sessions}{%
\section{Sessions}\label{shiny-intro-sessions}}

Note that shiny isolate each client connecting to the server in what it refers to as ``sessions.'' This means that when a user visits a shiny application and interacts with the inputs, like clicking a button, or moving a slider this only happens for their session, in their browser, and not in any other users'.

It would indeed be strange if when one of two concurrent users enters text in a box and that is reflected on the other user's screen.

This is good to know because WebSocket\index{WebSocket} are in fact often use for precisely that effect. For instance, in a chat application where someone posting a message to a group chat is sent to the server which then, via the WebSocket, \emph{broadcasts} the message to all other users in the group chat.

Shiny\index{Shiny} does not allow this, users are isolated from one another.

\hypertarget{shiny-intro-example}{%
\section{Alerts, an example}\label{shiny-intro-example}}

Let us exploit an external library to demonstrate how this works: \href{https://github.com/StephanWagner/jBox}{jBox} allows displaying ``notices,'' similar to vanilla JavaScript alerts but much better looking and with additional functionalities.

The grand scheme is to build an application that displays a notification at the click of an \texttt{actionButton} and ``tells'' the server when it is closed. Though the introduction of this book includes best practices on how to include dependencies and JavaScript files, much of that will be disregarded in this section (and only in this section). That is only so it does not get in the way of explaining bidirectional communication through the WebSocket in Shiny.

Moreover, the jBox library comes with numerous features to display tooltips, modals, notices, and more, which would make for too long a chapter; only notices shall be covered here. Let us first take a look at the code that generates a jBox notice.

\hypertarget{shiny-intro-explore}{%
\subsection{Explore}\label{shiny-intro-explore}}

Below we build an elementary example that features jBox in HTML; it includes the dependencies and a short script that displays a notification when the page is loaded.

\begin{Shaded}
\begin{Highlighting}[]
\DataTypeTok{<!DOCTYPE }\NormalTok{html}\DataTypeTok{>}
\KeywordTok{<html}\OtherTok{ xmlns=}\StringTok{"http://www.w3.org/1999/xhtml"}\OtherTok{ lang=}\StringTok{""}\OtherTok{ xml:lang=}\StringTok{""}\KeywordTok{>}
\KeywordTok{<head>}
\KeywordTok{<script} 
\OtherTok{  src=}\StringTok{"https://code.jquery.com/jquery-3.5.1.min.js"}\KeywordTok{>}
  \KeywordTok{</script>}
\KeywordTok{<script} 
\OtherTok{  src=}\StringTok{"https://cdn.jsdelivr.net/gh/StephanWagner/jBox@v1.2.0/}
\StringTok{    dist/jBox.all.min.js"}\KeywordTok{>}
\KeywordTok{</script>}
\KeywordTok{<link} 
\OtherTok{  href=}\StringTok{"https://cdn.jsdelivr.net/gh/StephanWagner/jBox@v1.2.0/}
\StringTok{    dist/jBox.all.min.css"} 
\OtherTok{  rel=}\StringTok{"stylesheet"}\KeywordTok{>}
\KeywordTok{</head>}

\KeywordTok{<body>}
  \CommentTok{<!-- Script to show a notification -->}
  \KeywordTok{<script>}
    \KeywordTok{new} \AttributeTok{jBox}\NormalTok{(}\StringTok{'Notice'}\OperatorTok{,} \OperatorTok{\{}
      \DataTypeTok{content}\OperatorTok{:} \StringTok{'Hurray! A notice!'}
    \OperatorTok{\}}\NormalTok{)}\OperatorTok{;}
  \KeywordTok{</script>}
\KeywordTok{</body>}
\KeywordTok{</html>}
\end{Highlighting}
\end{Shaded}

The very first thing one should do is recreate this basic example in Shiny so that when the app is loaded the notification appears, we will make this work with the bidirectional WebSocket communication afterwards. The ``j'' in jBox stands for jQuery, which is already a dependency of Shiny itself. There is, therefore, no need to import it; on the contrary one should not in order to avoid clashes.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(shiny)}

\NormalTok{ui <-}\StringTok{ }\KeywordTok{fluidPage}\NormalTok{(}
\NormalTok{  tags}\OperatorTok{$}\KeywordTok{head}\NormalTok{(}
\NormalTok{    tags}\OperatorTok{$}\KeywordTok{script}\NormalTok{(}
      \DataTypeTok{src =} \KeywordTok{paste0}\NormalTok{(}
        \StringTok{"https://cdn.jsdelivr.net/gh/StephanWagner/"}\NormalTok{,}
        \StringTok{"jBox@v1.2.0/dist/jBox.all.min.js"}
\NormalTok{      )}
\NormalTok{    ),}
\NormalTok{    tags}\OperatorTok{$}\KeywordTok{link}\NormalTok{(}
      \DataTypeTok{rel =} \StringTok{"stylesheet"}\NormalTok{,}
      \DataTypeTok{href =} \KeywordTok{paste0}\NormalTok{(}
        \StringTok{"https://cdn.jsdelivr.net/gh/StephanWagner/"}\NormalTok{,}
        \StringTok{"jBox@v1.2.0/dist/jBox.all.min.css"}
\NormalTok{      )}
\NormalTok{    )}
\NormalTok{  ),}
\NormalTok{  tags}\OperatorTok{$}\KeywordTok{script}\NormalTok{(}\StringTok{"}
\StringTok{    new jBox('Notice', \{}
\StringTok{      content: 'Hurray! A notice!'}
\StringTok{    \});"}
\NormalTok{  )}
\NormalTok{)}

\NormalTok{server <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(input, output) \{\}}

\KeywordTok{shinyApp}\NormalTok{(ui, server)}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/jbox-init} 

}

\caption{A basic jBox notice}\label{fig:jbox-init}
\end{figure}

Figure \ref{fig:jbox-init}, and the application above essentially reproduce the basic HTML example that was shared; the dependencies are imported, and a script displays a notification. Since all of that takes place in the front end, the body of the server function is empty.

\hypertarget{shiny-intro-r-to-js}{%
\subsection{From R to JavaScript}\label{shiny-intro-r-to-js}}

Now that we have a simple notice displayed in the application we can tie it with the R server the alert should display a message sent by the R server. This would enable more dynamic messages, such as displaying a message taken from a database or a user input. As might be expected, there are two functions required to do so: an R function and its JavaScript complementary. One sends the data from the server and another catches said data in the client and displays the notice.

Let us start by writing the R code to send the data---thankfully very little is required of the developer. One can send data from the R server to the client from the \texttt{session} object using the \texttt{sendCustomMessage} method. Note that being a method of the \texttt{session} object implies that this message will only be sent to said session: only the client connected to that session will receive the message.

The \texttt{sendCustomMessage} method takes two arguments: first an identifier (\texttt{type}), second the actual data to send to JavaScript (\texttt{message}). The identifier passed first will be necessary JavaScript-side to ``catch'' that message and show the notice.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{server <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(input, output, session)\{}
  \CommentTok{# set the identifier to send-notice}
\NormalTok{  session}\OperatorTok{$}\KeywordTok{sendCustomMessage}\NormalTok{(}
    \DataTypeTok{type =} \StringTok{"send-notice"}\NormalTok{, }\DataTypeTok{message =} \StringTok{"Hi there!"}
\NormalTok{  )}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

So while the above sends the message to JavaScript through the WebSocket, nothing is yet to be done with that message once it arrives in the client. We can add a ``handler'' for the identifier we defined (\texttt{send-notice}) which will do something with the message we sent from the server. This is done with the \texttt{addCustomMessageHandler} method from the \texttt{Shiny} object, where the first argument is the identifier and the second is the function that handles the message, a function that takes a single argument: the data sent from the server.

Below we add the handler for messages of type \texttt{send-notice}; the handler itself is a function that accepts the messages that were sent from the server and uses it to generate the notice via jBox.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{tags}\OperatorTok{$}\KeywordTok{script}\NormalTok{(}
  \StringTok{"Shiny.addCustomMessageHandler(}
\StringTok{    type = 'send-notice', function(message) \{}
\StringTok{      new jBox('Notice', \{}
\StringTok{        content: message}
\StringTok{      \});}
\StringTok{  \});"}
\NormalTok{)}
\end{Highlighting}
\end{Shaded}

This effectively enables passing a message that is taken from a database, for instance, or as shown below from a user input, to the front end, which generates a notice.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(shiny)}

\NormalTok{ui <-}\StringTok{ }\KeywordTok{fluidPage}\NormalTok{(}
\NormalTok{  tags}\OperatorTok{$}\KeywordTok{head}\NormalTok{(}
\NormalTok{    tags}\OperatorTok{$}\KeywordTok{script}\NormalTok{(}
      \DataTypeTok{src =} \KeywordTok{paste0}\NormalTok{(}
        \StringTok{"https://cdn.jsdelivr.net/gh/StephanWagner/"}\NormalTok{,}
        \StringTok{"jBox@v1.2.0/dist/jBox.all.min.js"}
\NormalTok{      )}
\NormalTok{    ),}
\NormalTok{    tags}\OperatorTok{$}\KeywordTok{link}\NormalTok{(}
      \DataTypeTok{rel =} \StringTok{"stylesheet"}\NormalTok{,}
      \DataTypeTok{href =} \KeywordTok{paste0}\NormalTok{(}
        \StringTok{"https://cdn.jsdelivr.net/gh/StephanWagner/"}\NormalTok{,}
        \StringTok{"jBox@v1.2.0/dist/jBox.all.min.css"}
\NormalTok{      )}
\NormalTok{    )}
\NormalTok{  ),}
  \KeywordTok{textInput}\NormalTok{(}\StringTok{"msg"}\NormalTok{, }\StringTok{"notice"}\NormalTok{),}
  \KeywordTok{actionButton}\NormalTok{(}\StringTok{"notify"}\NormalTok{, }\StringTok{"Notify myself"}\NormalTok{),}
\NormalTok{  tags}\OperatorTok{$}\KeywordTok{script}\NormalTok{(}
    \StringTok{"Shiny.addCustomMessageHandler(}
\StringTok{      type = 'send-notice', function(message) \{}
\StringTok{        new jBox('Notice', \{}
\StringTok{          content: message}
\StringTok{        \});}
\StringTok{    \});"}
\NormalTok{  )}
\NormalTok{)}

\NormalTok{server <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(input, output, session) \{}

  \KeywordTok{observeEvent}\NormalTok{(input}\OperatorTok{$}\NormalTok{notify, \{}
\NormalTok{    session}\OperatorTok{$}\KeywordTok{sendCustomMessage}\NormalTok{(}
      \DataTypeTok{type =} \StringTok{"send-notice"}\NormalTok{, }\DataTypeTok{message =}\NormalTok{ input}\OperatorTok{$}\NormalTok{msg}
\NormalTok{    )}
\NormalTok{  \})}

\NormalTok{\}}

\KeywordTok{shinyApp}\NormalTok{(ui, server)}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/jbox-r2js} 

}

\caption{A notice triggered by the server}\label{fig:jbox-r2js}
\end{figure}

In the previous application that produces Figure \ref{fig:shiny-alert-diagram}, notice the path that the message follows: it goes from the client (user input) to the server (\texttt{observeEvent}), which sends (\texttt{sendCustomMessage}) it back to the client.

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/04-custom-msg} 

}

\caption{Shiny alert with custom messages}\label{fig:shiny-alert-diagram}
\end{figure}

This might be considered suboptimal by some as it is not necessary to use the server as an intermediary (in this example at least). Though there is some truth to this, the above will work perfectly fine---and the aim here is to make JavaScript work with R---not alongside it. The WebSocket\index{WebSocket} is very efficient, and this will not have much overhead at all.

\hypertarget{shiny-intro-serialise}{%
\subsection{Serialisation}\label{shiny-intro-serialise}}

Let us delve deeper into the data that is sent from the server to the front end to understand how we can further customise the notice displayed, e.g., change the colour.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{new} \AttributeTok{jBox}\NormalTok{(}\StringTok{'Notice'}\OperatorTok{,} \OperatorTok{\{}
  \DataTypeTok{content}\OperatorTok{:} \StringTok{'Hurray! A notice!'}\OperatorTok{,}
  \DataTypeTok{color}\OperatorTok{:} \StringTok{'red'}
\OperatorTok{\}}\NormalTok{)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

The jBox notice is configured using a JSON object containing the options that define said notice to display (example above), including but not limited to the message. The most straightforward way to make all those options accessible to the server is to construct that list of options server-side before sending it to the front end. For instance, the JSON\index{JSON} of options displayed above would look like the R list below.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{options <-}\StringTok{ }\KeywordTok{list}\NormalTok{(}
  \DataTypeTok{content =} \StringTok{'Hurray! A notice!'}\NormalTok{,}
  \DataTypeTok{color =} \StringTok{'red'}
\NormalTok{)}
\NormalTok{jsonlite}\OperatorTok{::}\KeywordTok{toJSON}\NormalTok{(options, }\DataTypeTok{pretty =} \OtherTok{TRUE}\NormalTok{, }\DataTypeTok{auto_unbox =} \OtherTok{TRUE}\NormalTok{)}
\CommentTok{#> \{}
\CommentTok{#>   "content": "Hurray! A notice!",}
\CommentTok{#>   "color": "red"}
\CommentTok{#> \}}
\end{Highlighting}
\end{Shaded}

Therefore, one could construct this list server-side and use it in jBox straight-away. Doing so means the JavaScript code can be simplified to \texttt{new\ jBox(\textquotesingle{}Notice\textquotesingle{},\ message);} and produce Figure \ref{fig:jbox-custom}.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(shiny)}

\NormalTok{ui <-}\StringTok{ }\KeywordTok{fluidPage}\NormalTok{(}
\NormalTok{  tags}\OperatorTok{$}\KeywordTok{head}\NormalTok{(}
\NormalTok{    tags}\OperatorTok{$}\KeywordTok{script}\NormalTok{(}
      \DataTypeTok{src =} \KeywordTok{paste0}\NormalTok{(}
        \StringTok{"https://cdn.jsdelivr.net/gh/StephanWagner/"}\NormalTok{,}
        \StringTok{"jBox@v1.2.0/dist/jBox.all.min.js"}
\NormalTok{      )}
\NormalTok{    ),}
\NormalTok{    tags}\OperatorTok{$}\KeywordTok{link}\NormalTok{(}
      \DataTypeTok{rel =} \StringTok{"stylesheet"}\NormalTok{,}
      \DataTypeTok{href =} \KeywordTok{paste0}\NormalTok{(}
        \StringTok{"https://cdn.jsdelivr.net/gh/StephanWagner/"}\NormalTok{,}
        \StringTok{"jBox@v1.2.0/dist/jBox.all.min.css"}
\NormalTok{      )}
\NormalTok{    ),}
\NormalTok{    tags}\OperatorTok{$}\KeywordTok{script}\NormalTok{(}\StringTok{"Shiny.addCustomMessageHandler(}
\StringTok{      type = 'send-notice', function(message) \{}
\StringTok{        // use notice send from the server}
\StringTok{        new jBox('Notice', message);}
\StringTok{    \});"}\NormalTok{)}
\NormalTok{  )}
\NormalTok{)}

\NormalTok{server <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(input, output, session)\{}
  \CommentTok{# define notice options}
\NormalTok{  notice =}\StringTok{ }\KeywordTok{list}\NormalTok{(}
    \DataTypeTok{content =} \StringTok{'Hello from the server'}\NormalTok{,}
    \DataTypeTok{color =} \StringTok{'black'}
\NormalTok{  )}
  \CommentTok{# send the notice}
\NormalTok{  session}\OperatorTok{$}\KeywordTok{sendCustomMessage}\NormalTok{(}
    \DataTypeTok{type =} \StringTok{"send-notice"}\NormalTok{, }\DataTypeTok{message =}\NormalTok{ notice}
\NormalTok{  )}
\NormalTok{\}}

\KeywordTok{shinyApp}\NormalTok{(ui, server)}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/jbox-custom} 

}

\caption{Customised jBox notice}\label{fig:jbox-custom}
\end{figure}

\hypertarget{shiny-intro-js2r}{%
\subsection{JavaScript to R}\label{shiny-intro-js2r}}

Thus far we have covered how to pass data from the R server to JavaScript in order to display a notification, but we have yet to make the data travel the other way: from JavaScript to R. In this example, we would like to send data from JavaScript to R when the notice is closed (either by itself or the user).

One ubiquitous way that such feedback is enabled in JavaScript is through events and callback functions, which are triggered upon an action being performed by the user (like the click of a button) or when other interesting things happen in the code. jBox provides numerous such \href{https://stephanwagner.me/jBox/options\#events}{events} so functions can be used when a modal is created or when a notice is closed, for instance.

The concept of the callback function is not totally foreign to R, albeit rarely used. For instance, Shiny comes with this feature, \texttt{shiny::onStop} and \texttt{shiny::onStart}. These allow having functions run when the application starts or exits, very useful to clean up and close database connections when the app exits.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{server <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(input, output)\{}
\NormalTok{  shiny}\OperatorTok{::}\KeywordTok{onStop}\NormalTok{(}
    \CommentTok{# callback function fired when app is closed}
    \ControlFlowTok{function}\NormalTok{()\{}
      \KeywordTok{cat}\NormalTok{(}\StringTok{"App has been closed"}\NormalTok{)}
\NormalTok{    \}}
\NormalTok{  )}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

In jBox, these callback functions are included in the JSON of options; below the \texttt{onClose} event is fired when the notice is closed.

\begin{Shaded}
\begin{Highlighting}[]
\OperatorTok{\{}
  \DataTypeTok{content}\OperatorTok{:} \StringTok{'Alert!'}\OperatorTok{,}
  \DataTypeTok{onClose}\OperatorTok{:} \KeywordTok{function}\NormalTok{()}\OperatorTok{\{}
    \CommentTok{// Fired when closed }
    \VariableTok{console}\NormalTok{.}\AttributeTok{log}\NormalTok{(}\StringTok{'Alert is closed'}\NormalTok{)}\OperatorTok{;}
  \OperatorTok{\}}
\OperatorTok{\}}
\end{Highlighting}
\end{Shaded}

This raises one issue: one cannot truly serialise\index{serialise} to executable code. The attempt below serialises the function to a string that \emph{will not} be evaluated in JavaScript, just like \texttt{"function(x)\{\ x\ +\ 1\ \}"} is not evaluated in R: it is not a function, it is a string.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# try to serialise an R function}
\NormalTok{jsonlite}\OperatorTok{::}\KeywordTok{toJSON}\NormalTok{(}\StringTok{"function(x)\{x + 1\}"}\NormalTok{, }\DataTypeTok{auto_unbox =} \OtherTok{TRUE}\NormalTok{)}
\CommentTok{#> "function(x)\{x + 1\}"}
\end{Highlighting}
\end{Shaded}

One solution is to append the callback function to the object of options JavaScript-side.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{tags}\OperatorTok{$}\KeywordTok{script}\NormalTok{(}\StringTok{"Shiny.addCustomMessageHandler(}
\StringTok{  type = 'send-alert', function(message) \{}
\StringTok{    // append callback}
\StringTok{    message.onClose = function()\{}
\StringTok{      // TODO send data back to R}
\StringTok{    \}}
\StringTok{    new jBox('Notice', message);}
\StringTok{\});"}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

Placing a function inside a JSON object is expected in JavaScript, in contrast with R where though it works it is rarely if ever done (reference class/R6 are somewhat similar). The above JavaScript code to append the callback function could look something like the snippet below in R.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{message <-}\StringTok{ }\KeywordTok{list}\NormalTok{(}\DataTypeTok{content =} \StringTok{"hello"}\NormalTok{)}
\NormalTok{message}\OperatorTok{$}\NormalTok{onClose <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(msg)\{}
  \KeywordTok{print}\NormalTok{(msg)}
\NormalTok{\}}
\NormalTok{message}\OperatorTok{$}\KeywordTok{onClose}\NormalTok{(}\StringTok{"Closing!"}\NormalTok{)}
\CommentTok{#> [1] "Closing!"}
\end{Highlighting}
\end{Shaded}

This explains how the event is used in jBox (and many other libraries), but the body of the callback used previously is empty and therefore will not do anything: we need it to send data back to the R server so it can be notified when the notice is closed.

This can be done by defining a simplified Shiny input. While the book will eventually cover fully-fledged Shiny\index{Shiny} inputs that can be registered, updated, and more, there is also a simplified version of the latter, which allows sending reactive input values to the server, where it can be used just like any other inputs (\texttt{input\$id}). The value of the input can be defined using the \texttt{setInputValue} method, which takes the \texttt{id} of the input and the \texttt{value} to give it.

Below place \texttt{Shiny.setInputValue(\textquotesingle{}notice\_close\textquotesingle{},\ true)} in the body of the function so the input \texttt{input\$notice\_close} will be set to \texttt{TRUE} when the notice closes.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{tags}\OperatorTok{$}\KeywordTok{script}\NormalTok{(}\StringTok{"Shiny.addCustomMessageHandler(}
\StringTok{  type = 'send-alert', function(message) \{}
\StringTok{    // append callback}
\StringTok{    message.onClose = function()\{}
\StringTok{      Shiny.setInputValue('notice_close', true);}
\StringTok{    \}}
\StringTok{    new jBox('Notice', message);}
\StringTok{\});"}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

However, Shiny internally optimises how those values are set. First, if the input is set to the same value, then Shiny ignores it. This is fine if you are interested in the actual value of the input but will not work as expected if the input is to be used as an event. Indeed if you want to use this input in an \texttt{observe}, \texttt{observeEvent}, or \texttt{eventReactive}, you want it to be triggered every time the input changes, regardless of whether that value is the same as before. The second optimisation Shiny does is when the input is set to multiple different values before these have been processed, then only the most recent value will actually be sent to the server.

One can opt-out of these optimisations using the \texttt{priority:\ "event"} option when setting the input value, which is what we shall do here. We are not interested in the actual value of that input \texttt{TRUE}; we want to make sure the server gets notified every time a notification closes and given the aforementioned optimisations, it will not. The first time the event will be fired the input will be set from \texttt{NULL} to \texttt{TRUE}, but every subsequent notification that close will not fire that event since the value will not change (it's always sending \texttt{TRUE} to the server).

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{tags}\OperatorTok{$}\KeywordTok{script}\NormalTok{(}\StringTok{"Shiny.addCustomMessageHandler(}
\StringTok{  type = 'send-alert', function(message) \{}
\StringTok{    // append callback}
\StringTok{    message.onClose = function()\{}
\StringTok{      Shiny.setInputValue(}
\StringTok{        'notice_close', true, \{priority: 'event'\}}
\StringTok{      );}
\StringTok{    \}}
\StringTok{    new jBox('Notice', message);}
\StringTok{\});"}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

That done it can be incorporated into the application (Figure \ref{fig:jbox-end}) built thus far. Something interesting could be done server-side, but to keep things brief and straightforward, we merely print the value of the input to the R console.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(shiny)}

\NormalTok{ui <-}\StringTok{ }\KeywordTok{fluidPage}\NormalTok{(}
\NormalTok{  tags}\OperatorTok{$}\KeywordTok{head}\NormalTok{(}
\NormalTok{    tags}\OperatorTok{$}\KeywordTok{script}\NormalTok{(}
      \DataTypeTok{src =} \KeywordTok{paste0}\NormalTok{(}
        \StringTok{"https://cdn.jsdelivr.net/gh/StephanWagner/"}\NormalTok{,}
        \StringTok{"jBox@v1.2.0/dist/jBox.all.min.js"}
\NormalTok{      )}
\NormalTok{    ),}
\NormalTok{    tags}\OperatorTok{$}\KeywordTok{link}\NormalTok{(}
      \DataTypeTok{rel =} \StringTok{"stylesheet"}\NormalTok{,}
      \DataTypeTok{href =} \KeywordTok{paste0}\NormalTok{(}
        \StringTok{"https://cdn.jsdelivr.net/gh/StephanWagner/"}\NormalTok{,}
        \StringTok{"jBox@v1.2.0/dist/jBox.all.min.css"}
\NormalTok{      )}
\NormalTok{    ),}
\NormalTok{    tags}\OperatorTok{$}\KeywordTok{script}\NormalTok{(}
      \StringTok{"Shiny.addCustomMessageHandler(}
\StringTok{        type = 'send-notice', function(message) \{}
\StringTok{          message.onClose = function()\{}
\StringTok{            Shiny.setInputValue(}
\StringTok{              'notice_close', true, \{priority: 'event'\}}
\StringTok{            );}
\StringTok{          \}}
\StringTok{          new jBox('Notice', message);}
\StringTok{      \});"}
\NormalTok{    )}
\NormalTok{  ),}
  \KeywordTok{textInput}\NormalTok{(}\StringTok{"msg"}\NormalTok{, }\StringTok{"A message to show as notice"}\NormalTok{),}
  \KeywordTok{actionButton}\NormalTok{(}\StringTok{"show"}\NormalTok{, }\StringTok{"Show the notice"}\NormalTok{)}
\NormalTok{)}

\NormalTok{server <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(input, output, session)\{}

  \KeywordTok{observeEvent}\NormalTok{(input}\OperatorTok{$}\NormalTok{show, \{}
    \CommentTok{# define notice options}
\NormalTok{    notice =}\StringTok{ }\KeywordTok{list}\NormalTok{(}
      \DataTypeTok{content =}\NormalTok{ input}\OperatorTok{$}\NormalTok{msg,}
      \DataTypeTok{color =} \StringTok{'black'}
\NormalTok{    )}

    \CommentTok{# send the notice}
\NormalTok{    session}\OperatorTok{$}\KeywordTok{sendCustomMessage}\NormalTok{(}
      \DataTypeTok{type =} \StringTok{"send-notice"}\NormalTok{, }\DataTypeTok{message =}\NormalTok{ notice}
\NormalTok{    )}
\NormalTok{  \})}

  \CommentTok{# print the output of the notice_close event (when fired)}
  \KeywordTok{observeEvent}\NormalTok{(input}\OperatorTok{$}\NormalTok{notice_close, \{}
    \KeywordTok{print}\NormalTok{(input}\OperatorTok{$}\NormalTok{notice_close)}
\NormalTok{  \})}
\NormalTok{\}}

\KeywordTok{shinyApp}\NormalTok{(ui, server)}
\end{Highlighting}
\end{Shaded}

\begin{verbatim}
#> [1] TRUE
\end{verbatim}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/jbox-end} 

}

\caption{jBox final application}\label{fig:jbox-end}
\end{figure}

In the next chapter, we will build another application that makes use of bidirectional communication but also introduces a few more concepts to improve how such communication takes place and allows passing more complex messages from R to JavaScript and vice versa.

\hypertarget{shiny-complete}{%
\chapter{A Complete Integration}\label{shiny-complete}}

Thus far, this part of the book has covered both ways data travels between JavaScript and R in Shiny\index{Shiny}. However, the notices displayed in the previous chapter, though they demonstrate how both languages can work together within Shiny, come short of illustrating some more advanced use cases, how to package such code and more.

We shall introduce a fascinating JavaScript library that enables running machine learning models in web browsers\index{web browser}: \href{https://learn.ml5js.org/}{ml5.js}. The library is a high-level interface to \href{https://www.tensorflow.org/js}{tensorflow.js} but very extensive as it includes a multitude of models to deal with sound, image, text, and more. In this chapter, one of those models is implemented, an image classifier using \href{https://arxiv.org/abs/1704.04861}{mobileNet} but the method shown can be used to integrate any other model later on.

This is not a gimmick; running a model this way means it runs in the client (web browsers) and not on the Shiny server, leaving it free to compute anything else and serve other concurrent users. It's also fast; JavaScript is often wrongly believed to be slow, on the contrary. Finally, the JavaScript API provided is straightforward; it's impressive how ml5.js exposes complex models through such a simple API.

For those who may already know TensorFlow and want to use a lower-level library, the genius of \href{https://www.tensorflow.org/js}{tensorflow.js} is that it runs on WebGL and is therefore GPU-accelerated; i.e., it's not slow, and has a very similar API to the TensorFlow Python library.

We start by exploring ml5.js, then plan the Shiny application that will make use of it, and finally, we wrap our work in the form of an R package.

\hypertarget{shiny-complete-discover}{%
\section{Discover}\label{shiny-complete-discover}}

As for all projects that involve external libraries, the very first thing to do is to scan the documentation to understand how it is used. The documentation of ml5.js is exemplary, filled with examples and crystal clear. \href{https://learn.ml5js.org/\#/reference/image-classifier}{It gives the following example} for the image classifier.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{// Initialize the Image Classifier method with MobileNet}
\KeywordTok{const}\NormalTok{ classifier }\OperatorTok{=} \VariableTok{ml5}\NormalTok{.}\AttributeTok{imageClassifier}\NormalTok{(}\StringTok{'MobileNet'}\OperatorTok{,}\NormalTok{ modelLoaded)}\OperatorTok{;}

\CommentTok{// When the model is loaded}
\KeywordTok{function} \AttributeTok{modelLoaded}\NormalTok{() }\OperatorTok{\{}
  \VariableTok{console}\NormalTok{.}\AttributeTok{log}\NormalTok{(}\StringTok{'Model Loaded!'}\NormalTok{)}\OperatorTok{;}
\OperatorTok{\}}

\CommentTok{// Make a prediction with a selected image}
\VariableTok{classifier}\NormalTok{.}\AttributeTok{classify}\NormalTok{(}
  \VariableTok{document}\NormalTok{.}\AttributeTok{getElementById}\NormalTok{(}\StringTok{'image'}\NormalTok{)}\OperatorTok{,}\NormalTok{ (err}\OperatorTok{,}\NormalTok{ results) }\KeywordTok{=>} \OperatorTok{\{}
    \VariableTok{console}\NormalTok{.}\AttributeTok{log}\NormalTok{(results)}\OperatorTok{;}
  \OperatorTok{\}}
\NormalTok{)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

First, the image \texttt{classifier} is initialised from the \texttt{ml5} object with the \texttt{imageClassifier} method. This method takes two arguments: the name of the pre-trained model to use (\texttt{MobileNet}) and a callback function that is run when the model is loaded. The \texttt{classify} method from the \texttt{classifier} is used with, again, two arguments: 1) the DOM\index{DOM} element that contains the image (\texttt{\textless{}img\ /\textgreater{}}) and 2) a callback function to do something with the results of the classification.

Now we can jump to the next section to think about how this can be implemented in Shiny\index{Shiny}.

\hypertarget{shiny-complete-setup}{%
\section{Setup}\label{shiny-complete-setup}}

In Shiny, a dropdown menu could be provided to choose from pre-selected images, and upon selection, the server renders the selected image. At the click of a button the model then runs and sends the results to the R server, which prints them in the UI (see Figure \ref{fig:shiny-complex-diagram}).

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/04-shiny-complex} 

}

\caption{Simple shiny app, complex communication}\label{fig:shiny-complex-diagram}
\end{figure}

This makes for what is probably a signature of Shiny: a considerable amount of bi-directional communication between the server and client as Shiny makes the most of the WebSocket\index{WebSocket}. Some readers with more advanced knowledge in JavaScript will find ways to avoid the use of the server in places to do more in the client; either way works.

\hypertarget{shiny-complete-dependencies}{%
\section{Dependencies}\label{shiny-complete-dependencies}}

The ml5.js framework and all its components are bundled in a single JavaScript file.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{<script}\OtherTok{ src=}\StringTok{"https://unpkg.com/ml5@0.4.3/dist/ml5.min.js"}\KeywordTok{></script>}
\end{Highlighting}
\end{Shaded}

We will create an \texttt{html\_dependency} object using the \texttt{htmlDependency}\index{dependency} function from the htmltools package. If confused, go back to the first part of the book on Shiny prerequisites, where it is explained in greater detail.

We have two options at our disposal either use the CDN (as shown in the previous code chunk) or download the file. We will start by making use of the CDN; later when we build a package for this functionality, we shall download it to provide users of the package a choice between using the local file or the CDN.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{dependency_ml5 <-}\StringTok{ }\NormalTok{htmltools}\OperatorTok{::}\KeywordTok{htmlDependency}\NormalTok{(}
  \DataTypeTok{name =} \StringTok{"ml5"}\NormalTok{,}
  \DataTypeTok{version =} \StringTok{"0.4.3"}\NormalTok{,}
  \DataTypeTok{src =} \KeywordTok{c}\NormalTok{(}\DataTypeTok{href =} \StringTok{"https://unpkg.com/ml5@0.4.3/dist/"}\NormalTok{),}
  \DataTypeTok{script =} \StringTok{"ml5.min.js"}
\NormalTok{)}
\end{Highlighting}
\end{Shaded}

\hypertarget{shiny-complete-images}{%
\section{Static Files}\label{shiny-complete-images}}

Images will, of course, be necessary in order to test the image classifier. We are therefore going to download some from Wikipedia. The following code chunk creates a directory of assets\index{asset}, downloads images of birds and saves them to the aforementioned directory. For brevity, we limit ourselves to downloading two images, one of a flamingo and another of a lorikeet, but feel free to add more. Also, note that the pre-trained image classifier we are going to use in this example is not limited to birds.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# static files directory}
\KeywordTok{dir.create}\NormalTok{(}\StringTok{"assets"}\NormalTok{)}

\CommentTok{# flamingo}
\NormalTok{fl <-}\StringTok{ }\KeywordTok{paste0}\NormalTok{(}
  \StringTok{"https://upload.wikimedia.org/wikipedia/"}\NormalTok{,}
  \StringTok{"commons/thumb/7/72/American_flamingo"}\NormalTok{,}
  \StringTok{"_%28Phoenicopterus_ruber%29.JPG/256px-"}\NormalTok{,}
  \StringTok{"American_flamingo_%28Phoenicopterus_ruber%29.JPG"}
\NormalTok{)}

\CommentTok{# lorikeet}
\NormalTok{lo <-}\StringTok{ }\KeywordTok{paste0}\NormalTok{(}
  \StringTok{"https://upload.wikimedia.org/wikipedia/"}\NormalTok{,}
  \StringTok{"commons/thumb/c/c2/Rainbow_lorikeet.jpg/"}\NormalTok{,}
  \StringTok{"256px-Rainbow_lorikeet.jpg"}
\NormalTok{)}

\CommentTok{# download}
\KeywordTok{download.file}\NormalTok{(fl, }\DataTypeTok{destfile =} \StringTok{"assets/flamingo.jpg"}\NormalTok{)}
\KeywordTok{download.file}\NormalTok{(lo, }\DataTypeTok{destfile =} \StringTok{"assets/lorikeet.jpg"}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

Finally we should also add a JavaScript file, which will eventually contain our custom functions to run the image classifier.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{file.create}\NormalTok{(}\StringTok{"www/classify.js"}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

At this stage, one should obtain a directory resembling the tree below.

\begin{verbatim}
.
├── app.R
└── assets
    ├── classify.js
    ├── flamingo.JPG
    └── lorikeet.jpg
\end{verbatim}

These files will eventually need to be served (\texttt{addResourcePath}), so they are accessible by the Shiny UI.

\hypertarget{shiny-complete-skeleton}{%
\section{Skeleton}\label{shiny-complete-skeleton}}

At this stage, it's probably good to build a skeleton of the application (Figure \ref{fig:shiny-complete-skeleton}).

After loading the Shiny\index{Shiny} package, we use the \texttt{addResourcePath} function to serve the images so they can be made accessible by the Shiny UI to display. At this stage, the application itself only provides a dropdown to select one of the two images previously downloaded, and a button to trigger the classification, which currently does not do anything, we'll delve into this next. Since we placed the \texttt{classify.js} JavaScript file in the \texttt{assets}\index{asset} directory we can also import it in the UI with a \texttt{script} tag; importantly this is done \emph{after} the ml5.js dependency\index{dependency} as it will depend on it. Another crucial thing that the app does is set the attribute \texttt{id} of the \texttt{\textless{}img\textgreater{}} to \texttt{bird} it is essential to have a convenient way to uniquely identify the image later on as ml5.js will need to read this image in order to classify it.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(shiny)}

\CommentTok{# serve images}
\KeywordTok{addResourcePath}\NormalTok{(}\StringTok{"assets"}\NormalTok{, }\StringTok{"assets"}\NormalTok{)}

\CommentTok{# ml5js dependency}
\NormalTok{dependency_ml5 <-}\StringTok{ }\NormalTok{htmltools}\OperatorTok{::}\KeywordTok{htmlDependency}\NormalTok{(}
  \DataTypeTok{name =} \StringTok{"ml5"}\NormalTok{,}
  \DataTypeTok{version =} \StringTok{"0.4.3"}\NormalTok{,}
  \DataTypeTok{src =} \KeywordTok{c}\NormalTok{(}\DataTypeTok{href =} \StringTok{"https://unpkg.com/ml5@0.4.3/dist/"}\NormalTok{),}
  \DataTypeTok{script =} \StringTok{"ml5.min.js"}
\NormalTok{)}

\NormalTok{ui <-}\StringTok{ }\KeywordTok{fluidPage}\NormalTok{(}
\NormalTok{  dependency_ml5,}
\NormalTok{  tags}\OperatorTok{$}\KeywordTok{head}\NormalTok{(}
\NormalTok{    tags}\OperatorTok{$}\KeywordTok{script}\NormalTok{(}\DataTypeTok{src =} \StringTok{"assets/classify.js"}\NormalTok{)}
\NormalTok{  ),}
  \KeywordTok{selectInput}\NormalTok{(}
    \DataTypeTok{inputId =} \StringTok{"selectedBird"}\NormalTok{, }
    \DataTypeTok{label =} \StringTok{"bird"}\NormalTok{,}
    \DataTypeTok{choices =} \KeywordTok{c}\NormalTok{(}\StringTok{"flamingo"}\NormalTok{, }\StringTok{"lorikeet"}\NormalTok{)}
\NormalTok{  ),}
  \KeywordTok{actionButton}\NormalTok{(}\StringTok{"classify"}\NormalTok{, }\StringTok{"Classify"}\NormalTok{),}
  \KeywordTok{uiOutput}\NormalTok{(}\StringTok{"birdDisplay"}\NormalTok{)}
\NormalTok{)}

\NormalTok{server <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(input, output, session) \{}

\NormalTok{  output}\OperatorTok{$}\NormalTok{birdDisplay <-}\StringTok{ }\KeywordTok{renderUI}\NormalTok{(\{}
\NormalTok{    path <-}\StringTok{ }\KeywordTok{sprintf}\NormalTok{(}\StringTok{"assets/%s.jpg"}\NormalTok{, input}\OperatorTok{$}\NormalTok{selectedBird)}
\NormalTok{    tags}\OperatorTok{$}\KeywordTok{img}\NormalTok{(}\DataTypeTok{src =}\NormalTok{ path, }\DataTypeTok{id =} \StringTok{"bird"}\NormalTok{)}
\NormalTok{  \})}

\NormalTok{\}}

\KeywordTok{shinyApp}\NormalTok{(ui, server)}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/shiny-complete-skeleton} 

}

\caption{Shiny app skeleton}\label{fig:shiny-complete-skeleton}
\end{figure}

\hypertarget{shiny-complete-r2js}{%
\section{From R to JavaScript}\label{shiny-complete-r2js}}

What is now left to do is to program the classification. As a reminder, when the ``classify'' button is clicked, the classification must happen JavaScript-side using ml5.js; this implies that data must travel from R to JavaScript.

This will be carried in a similar fashion as in the previous chapter on alerts; the R server needs to send a message to the front end so it can trigger the classification using JavaScript.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{observeEvent}\NormalTok{(input}\OperatorTok{$}\NormalTok{classify, \{}
\NormalTok{  session}\OperatorTok{$}\KeywordTok{sendCustomMessage}\NormalTok{(}\StringTok{"classify"}\NormalTok{, }\KeywordTok{list}\NormalTok{())}
\NormalTok{\})}
\end{Highlighting}
\end{Shaded}

We thus observe the button so that when clicked, a message is sent to the front end, via the WebSocket. Note that the \texttt{sendCustomMessage} method \textbf{must take data,} hence the empty \texttt{list} that is used as the second argument. That, of course, won't do anything as we are yet to add a handler in JavaScript to handle this \texttt{classify} message that is sent.

Looking back at the documentation of ml5.js, we observe that before we can classify the image, the model should be loaded: we start by placing this code in the \texttt{classify.js} application.

The classifier is initialised from the \texttt{imageClassifier} method, which takes 1) the pre-trained model to use (or its name), and 2) a callback function. The callback function is run when the model is done loading. Though we don't make use of it here the argument is not optional (omitting it will raise an error) so we pass a function that simply prints \texttt{Model\ Loaded!} to the console.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{// Mandatory callback function}
\KeywordTok{function} \AttributeTok{modelLoaded}\NormalTok{() }\OperatorTok{\{}
  \VariableTok{console}\NormalTok{.}\AttributeTok{log}\NormalTok{(}\StringTok{'Model Loaded!'}\NormalTok{)}\OperatorTok{;}
\OperatorTok{\}}

\CommentTok{// Initialize the Image Classifier method with MobileNet}
\KeywordTok{const}\NormalTok{ classifier }\OperatorTok{=} \VariableTok{ml5}\NormalTok{.}\AttributeTok{imageClassifier}\NormalTok{(}\StringTok{'MobileNet'}\OperatorTok{,}\NormalTok{ modelLoaded)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

\begin{rmdnote}
There is no need to repeatedly initialise the classifier every time a
user hits the ``classify'' button: this should only be done once.
\end{rmdnote}

Finally, we can take care of the message handler. Remember the message sent from the R server bears the \texttt{classify} unique identifier. The handler function runs the \texttt{classify} method on the previously instantiated \texttt{classifier} object. This takes 1) the image to classify and 2) a callback function to handle the results of the classification. Here we genuinely get to why we gave the generated \texttt{\textless{}img\textgreater{}} of the selected bird and \texttt{id}: it helps us quickly select that image from JavaScript to use in the classifier with \texttt{document.getElementById("bird")}.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{// Mandatory callback function}
\KeywordTok{function} \AttributeTok{modelLoaded}\NormalTok{() }\OperatorTok{\{}
  \VariableTok{console}\NormalTok{.}\AttributeTok{log}\NormalTok{(}\StringTok{'Model Loaded!'}\NormalTok{)}\OperatorTok{;}
\OperatorTok{\}}

\CommentTok{// Initialize the Image Classifier method with MobileNet}
\KeywordTok{const}\NormalTok{ classifier }\OperatorTok{=} \VariableTok{ml5}\NormalTok{.}\AttributeTok{imageClassifier}\NormalTok{(}\StringTok{'MobileNet'}\OperatorTok{,}\NormalTok{ modelLoaded)}\OperatorTok{;}

\VariableTok{Shiny}\NormalTok{.}\AttributeTok{addCustomMessageHandler}\NormalTok{(}\StringTok{'classify'}\OperatorTok{,} \KeywordTok{function}\NormalTok{(data)}\OperatorTok{\{}
  \CommentTok{// Classify bird}
  \VariableTok{classifier}\NormalTok{.}\AttributeTok{classify}\NormalTok{(}
    \VariableTok{document}\NormalTok{.}\AttributeTok{getElementById}\NormalTok{(}\StringTok{"bird"}\NormalTok{)}\OperatorTok{,}\NormalTok{ (err}\OperatorTok{,}\NormalTok{ results) }\KeywordTok{=>} \OperatorTok{\{}
      \VariableTok{console}\NormalTok{.}\AttributeTok{log}\NormalTok{(results)}
    \OperatorTok{\}}
\NormalTok{  )}\OperatorTok{;}
\OperatorTok{\}}\NormalTok{)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

As mentioned at the start of the chapter, the results of the classification should be sent back to the R server, but for now, we shall content ourselves with logging it in the console.

Running the application and opening the console (Figure \ref{fig:shiny-complete-classify-console}) already gives us encouraging results! The classifier gives ``flamingo'' the greatest confidence (albeit at \texttt{0.48}).

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/shiny-complete-classify-console} 

}

\caption{Results logged to the console}\label{fig:shiny-complete-classify-console}
\end{figure}

\hypertarget{shiny-complete-js2r}{%
\section{From JavaScript to R}\label{shiny-complete-js2r}}

The application thus classifies the images, but the results remain in the front end, and we would like to have those results returned to the R server so we can further process them and display them back to the user.

As in the previous chapter, this can be done with the \texttt{setInputValue} function, which, as a reminder, will do exactly as advertised: it will set an \texttt{input} with a given value in the R server. The code below will make it such that the \texttt{results} will be accessible in the R server with \texttt{input\$classification}.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{// Mandatory callback function}
\KeywordTok{function} \AttributeTok{modelLoaded}\NormalTok{() }\OperatorTok{\{}
  \VariableTok{console}\NormalTok{.}\AttributeTok{log}\NormalTok{(}\StringTok{'Model Loaded!'}\NormalTok{)}\OperatorTok{;}
\OperatorTok{\}}

\CommentTok{// Initialize the Image Classifier method with MobileNet}
\KeywordTok{const}\NormalTok{ classifier }\OperatorTok{=} \VariableTok{ml5}\NormalTok{.}\AttributeTok{imageClassifier}\NormalTok{(}\StringTok{'MobileNet'}\OperatorTok{,}\NormalTok{ modelLoaded)}\OperatorTok{;}

\VariableTok{Shiny}\NormalTok{.}\AttributeTok{addCustomMessageHandler}\NormalTok{(}\StringTok{'classify'}\OperatorTok{,} \KeywordTok{function}\NormalTok{(data)}\OperatorTok{\{}
  \CommentTok{// Classify bird}
  \VariableTok{classifier}\NormalTok{.}\AttributeTok{classify}\NormalTok{(}
    \VariableTok{document}\NormalTok{.}\AttributeTok{getElementById}\NormalTok{(}\StringTok{"bird"}\NormalTok{)}\OperatorTok{,}\NormalTok{ (err}\OperatorTok{,}\NormalTok{ results) }\KeywordTok{=>} \OperatorTok{\{}
      \VariableTok{Shiny}\NormalTok{.}\AttributeTok{setInputValue}\NormalTok{(}\StringTok{"classification"}\OperatorTok{,}\NormalTok{ results)}
    \OperatorTok{\}}
\NormalTok{  )}\OperatorTok{;}
\OperatorTok{\}}\NormalTok{)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

Now that the results are sent back to the R server, we can use them to display it back in the application (Figure \ref{fig:shiny-complete-ml5-output}) so users of the application may know how the model performed. We shall eventually make this prettier, but for now, we'll limit it to displaying the results in \texttt{verbatimTextOutput}.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(shiny)}

\CommentTok{# serve images}
\KeywordTok{addResourcePath}\NormalTok{(}\StringTok{"assets"}\NormalTok{, }\StringTok{"assets"}\NormalTok{)}

\CommentTok{# ml5js dependency}
\NormalTok{dependency_ml5 <-}\StringTok{ }\NormalTok{htmltools}\OperatorTok{::}\KeywordTok{htmlDependency}\NormalTok{(}
  \DataTypeTok{name =} \StringTok{"ml5"}\NormalTok{,}
  \DataTypeTok{version =} \StringTok{"0.4.3"}\NormalTok{,}
  \DataTypeTok{src =} \KeywordTok{c}\NormalTok{(}\DataTypeTok{href =} \StringTok{"https://unpkg.com/ml5@0.4.3/dist/"}\NormalTok{),}
  \DataTypeTok{script =} \StringTok{"ml5.min.js"}
\NormalTok{)}

\NormalTok{ui <-}\StringTok{ }\KeywordTok{fluidPage}\NormalTok{(}
\NormalTok{  dependency_ml5,}
\NormalTok{  tags}\OperatorTok{$}\KeywordTok{head}\NormalTok{(tags}\OperatorTok{$}\KeywordTok{script}\NormalTok{(}\DataTypeTok{src =} \StringTok{"assets/classify.js"}\NormalTok{)),}
  \KeywordTok{selectInput}\NormalTok{(}
    \DataTypeTok{inputId =} \StringTok{"selectedBird"}\NormalTok{, }
    \DataTypeTok{label =} \StringTok{"bird"}\NormalTok{,}
    \DataTypeTok{choices =} \KeywordTok{c}\NormalTok{(}\StringTok{"flamingo"}\NormalTok{, }\StringTok{"lorikeet"}\NormalTok{)}
\NormalTok{  ),}
  \KeywordTok{actionButton}\NormalTok{(}\StringTok{"classify"}\NormalTok{, }\StringTok{"Classify"}\NormalTok{),}
  \KeywordTok{uiOutput}\NormalTok{(}\StringTok{"birdDisplay"}\NormalTok{),}
  \KeywordTok{verbatimTextOutput}\NormalTok{(}\StringTok{"results"}\NormalTok{) }\CommentTok{# display results}
\NormalTok{)}

\NormalTok{server <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(input, output, session) \{}

\NormalTok{  output}\OperatorTok{$}\NormalTok{birdDisplay <-}\StringTok{ }\KeywordTok{renderUI}\NormalTok{(\{}
\NormalTok{    path <-}\StringTok{ }\KeywordTok{sprintf}\NormalTok{(}\StringTok{"assets/%s.jpg"}\NormalTok{, input}\OperatorTok{$}\NormalTok{selectedBird)}
\NormalTok{    tags}\OperatorTok{$}\KeywordTok{img}\NormalTok{(}\DataTypeTok{src =}\NormalTok{ path, }\DataTypeTok{id =} \StringTok{"bird"}\NormalTok{)}
\NormalTok{  \})}

  \KeywordTok{observeEvent}\NormalTok{(input}\OperatorTok{$}\NormalTok{classify, \{}
\NormalTok{    session}\OperatorTok{$}\KeywordTok{sendCustomMessage}\NormalTok{(}\StringTok{"classify"}\NormalTok{, }\KeywordTok{list}\NormalTok{())}
\NormalTok{  \})}

  \CommentTok{# render results}
\NormalTok{  output}\OperatorTok{$}\NormalTok{results <-}\StringTok{ }\KeywordTok{renderPrint}\NormalTok{(\{}
    \KeywordTok{print}\NormalTok{(input}\OperatorTok{$}\NormalTok{classification)}
\NormalTok{  \})}

\NormalTok{\}}

\KeywordTok{shinyApp}\NormalTok{(ui, server)}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/ml5-output} 

}

\caption{Classifier basic output}\label{fig:shiny-complete-ml5-output}
\end{figure}

\hypertarget{shiny-complete-input-handler}{%
\section{Input handler}\label{shiny-complete-input-handler}}

In the previous section on sending data from R to JavaScript, we used a ``message handler'' in JavaScript to handle the data coming from the server. There is also the corollary, an ``input handler'' to preprocess the data coming from JavaScript before it is made accessible by the input. In R, this is a function that must accept three arguments: the data coming to JavaScript, a Shiny\index{Shiny} session, and the name of the input. Note that all of these arguments are mandatory if they are not used in the function we can use the three-dot construct instead.

Input handlers are most often used to reshape or change the type of the data coming in. To demonstrate how to use them, we will reshape the classification results sent to R as looking at the results of the classification in the R server one might notice a row-wise list, which can be transformed into a \texttt{data.frame}. The function below makes use of the \href{https://github.com/tidyverse/purrr/}{purrr} \citep{R-purrr} package to loop over every result and transform them into data.frames and return a single data.frame.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# create handler}
\NormalTok{process_results <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(data, ...)\{}
\NormalTok{  purrr}\OperatorTok{::}\KeywordTok{map_dfr}\NormalTok{(data, as.data.frame)}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

Once this function created, it needs to be registered with Shiny using the \texttt{registerInputHandler} function, which takes two arguments. First, a unique identifier for the handler, second, the handler function. Attempt to give the handler a unique yet straightforward name (alphanumeric characters, underscores, and periods) to avoid clashes with other handlers.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# register with shiny}
\NormalTok{shiny}\OperatorTok{::}\KeywordTok{registerInputHandler}\NormalTok{(}\StringTok{"ml5.class"}\NormalTok{, process_results)}
\end{Highlighting}
\end{Shaded}

Note that handlers can only be registered once; running the above twice will fail the second time, even if the handler function has changed. This is to ensure one does not accidentally overwrite handlers brought in by other packages. These can be overwritten by explicitly setting \texttt{force} to \texttt{TRUE}, but it is not advised.

\begin{rmdnote}
It is not advised to overwrite the registered handler.
\end{rmdnote}

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# register with shiny}
\KeywordTok{registerInputHandler}\NormalTok{(}\StringTok{"ml5.class"}\NormalTok{, process_results)}
\end{Highlighting}
\end{Shaded}

Once the handler function is created and registered with Shiny, what is left to do is tell Shiny which input should use that handler. This is done by adding the name of the handler, \texttt{ml5.class}, preceded by a colon (\texttt{:ml5.class}) as a suffix to the input name.

\begin{Shaded}
\begin{Highlighting}[]
\VariableTok{Shiny}\NormalTok{.}\AttributeTok{addCustomMessageHandler}\NormalTok{(}\StringTok{'classify'}\OperatorTok{,} \KeywordTok{function}\NormalTok{(data)}\OperatorTok{\{}
  \CommentTok{// Classify bird}
  \VariableTok{classifier}\NormalTok{.}\AttributeTok{classify}\NormalTok{(}
    \VariableTok{document}\NormalTok{.}\AttributeTok{getElementById}\NormalTok{(}\StringTok{"bird"}\NormalTok{)}\OperatorTok{,}\NormalTok{ (err}\OperatorTok{,}\NormalTok{ results) }\KeywordTok{=>} \OperatorTok{\{}
      \VariableTok{Shiny}\NormalTok{.}\AttributeTok{setInputValue}\NormalTok{(}\StringTok{"classification:ml5.class"}\OperatorTok{,}\NormalTok{ results)}\OperatorTok{;}
    \OperatorTok{\}}
\NormalTok{  )}\OperatorTok{;}
\OperatorTok{\}}\NormalTok{)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

Now that the results of \texttt{input\$classification} is a data.frame we can display the results in a neat table instead, as shown in Figure \ref{fig:shiny-complete-table-output}.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(shiny)}

\CommentTok{# serve images}
\KeywordTok{addResourcePath}\NormalTok{(}\StringTok{"assets"}\NormalTok{, }\StringTok{"assets"}\NormalTok{)}

\CommentTok{# create handler}
\NormalTok{handler <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(data, ...)\{}
\NormalTok{  purrr}\OperatorTok{::}\KeywordTok{map_dfr}\NormalTok{(data, as.data.frame)}
\NormalTok{\}}

\CommentTok{# register with shiny}
\NormalTok{shiny}\OperatorTok{::}\KeywordTok{registerInputHandler}\NormalTok{(}\StringTok{"ml5.class"}\NormalTok{, handler)}

\CommentTok{# ml5js dependency}
\NormalTok{dependency_ml5 <-}\StringTok{ }\NormalTok{htmltools}\OperatorTok{::}\KeywordTok{htmlDependency}\NormalTok{(}
  \DataTypeTok{name =} \StringTok{"ml5"}\NormalTok{,}
  \DataTypeTok{version =} \StringTok{"0.4.3"}\NormalTok{,}
  \DataTypeTok{src =} \KeywordTok{c}\NormalTok{(}\DataTypeTok{href =} \StringTok{"https://unpkg.com/ml5@0.4.3/dist/"}\NormalTok{),}
  \DataTypeTok{script =} \StringTok{"ml5.min.js"}
\NormalTok{)}

\NormalTok{ui <-}\StringTok{ }\KeywordTok{fluidPage}\NormalTok{(}
\NormalTok{  dependency_ml5,}
\NormalTok{  tags}\OperatorTok{$}\KeywordTok{head}\NormalTok{(tags}\OperatorTok{$}\KeywordTok{script}\NormalTok{(}\DataTypeTok{src =} \StringTok{"assets/classify.js"}\NormalTok{)),}
  \KeywordTok{selectInput}\NormalTok{(}
    \DataTypeTok{inputId =} \StringTok{"selectedBird"}\NormalTok{, }
    \DataTypeTok{label =} \StringTok{"bird"}\NormalTok{,}
    \DataTypeTok{choices =} \KeywordTok{c}\NormalTok{(}\StringTok{"flamingo"}\NormalTok{, }\StringTok{"lorikeet"}\NormalTok{)}
\NormalTok{  ),}
  \KeywordTok{actionButton}\NormalTok{(}\StringTok{"classify"}\NormalTok{, }\StringTok{"Classify"}\NormalTok{),}
  \KeywordTok{uiOutput}\NormalTok{(}\StringTok{"birdDisplay"}\NormalTok{),}
  \KeywordTok{tableOutput}\NormalTok{(}\StringTok{"results"}\NormalTok{)}
\NormalTok{)}

\NormalTok{server <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(input, output, session) \{}

\NormalTok{  output}\OperatorTok{$}\NormalTok{birdDisplay <-}\StringTok{ }\KeywordTok{renderUI}\NormalTok{(\{}
\NormalTok{    path <-}\StringTok{ }\KeywordTok{sprintf}\NormalTok{(}\StringTok{"assets/%s.jpg"}\NormalTok{, input}\OperatorTok{$}\NormalTok{selectedBird)}
\NormalTok{    tags}\OperatorTok{$}\KeywordTok{img}\NormalTok{(}\DataTypeTok{src =}\NormalTok{ path, }\DataTypeTok{id =} \StringTok{"bird"}\NormalTok{)}
\NormalTok{  \})}

  \KeywordTok{observeEvent}\NormalTok{(input}\OperatorTok{$}\NormalTok{classify, \{}
\NormalTok{    session}\OperatorTok{$}\KeywordTok{sendCustomMessage}\NormalTok{(}\StringTok{"classify"}\NormalTok{, }\KeywordTok{list}\NormalTok{())}
\NormalTok{  \})}

\NormalTok{  output}\OperatorTok{$}\NormalTok{results <-}\StringTok{ }\KeywordTok{renderTable}\NormalTok{(\{}
\NormalTok{    input}\OperatorTok{$}\NormalTok{classification}
\NormalTok{  \})}

\NormalTok{\}}

\KeywordTok{shinyApp}\NormalTok{(ui, server)}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/shiny-complete-table} 

}

\caption{Classifier table output}\label{fig:shiny-complete-table-output}
\end{figure}

\hypertarget{shiny-complete-pkg}{%
\section{As a Package}\label{shiny-complete-pkg}}

This chapter thus far built a nice application, but the code written is hardly portable; were one to make use of the image classifier from ml5.js in another application, everything would have to be rewritten or copy-pasted, which is hardly good practice and not remotely convenient. Instead this code should be packaged, so it is easily reusable and shareable. Moreover, this will benefit from all the other advantages that R packages bring to code such as documentation, reproducibility, and tests. This also forces the developer to think about the code differently. As we'll discover it's not as simple as wrapping individual functionalities from the app into functions.

Before we delve into building the package, let us think through what it should include. The application using ml5 gives some indication as to what the package will look like. Users of the package should be able to reproduce what is executed in the application, namely import dependencies\index{dependency} (including the ``message handler''), send data to the JavaScript front end to trigger the classification, and then obtain the results in the R server.

We start by creating a package called \texttt{ml5}.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{usethis}\OperatorTok{::}\KeywordTok{create_package}\NormalTok{(}\StringTok{"ml5"}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

\hypertarget{shiny-complete-pkg-deps}{%
\subsection{Dependencies}\label{shiny-complete-pkg-deps}}

In the application, the web-hosted dependencies (CDN\index{CDN}) were used. There are two advantages to using CDNs: 1) it's just convenient as one does not have to download them, 2) it's fast---CDNs are distributed geographically to improve the speed at which they serve the dependencies\index{dependency} and will therefore generally outperform the alternative, serving the files locally. This may raise questions when building a package though, as one generally wants these to be as modular, self-contained, and reproducible as possible, and none of these things go well with the idea of a remotely served dependency\index{dependency} that is absolutely central to the package. The package should therefore provide both ways of importing dependencies: via the CDN or using locally-stored files. The former will be faster while the latter can be used as a fallback in the event there is an issue with the CDN or one does not have internet for instance.

We can download the dependency\index{dependency} hosted on the CDN\index{CDN} and place it in the \texttt{inst} directory of the package. We also create another JavaScript \texttt{classify.js} that will contain the custom JavaScript code (message handler, etc.) as was done for the application.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# create directory}
\KeywordTok{dir.create}\NormalTok{(}\StringTok{"inst"}\NormalTok{)}

\CommentTok{# download dependency}
\NormalTok{uri <-}\StringTok{ "https://unpkg.com/ml5@0.4.3/dist/ml5.min.js"}
\KeywordTok{download.file}\NormalTok{(uri, }\DataTypeTok{destfile =} \StringTok{"inst/ml5.min.js"}\NormalTok{)}

\CommentTok{# create js file }
\KeywordTok{file.create}\NormalTok{(}\StringTok{"inst/classify.js"}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

With the dependencies locally downloaded one can move on to create the R function that will be used to import the dependencies\index{dependency} in the Shiny UI. The file \texttt{classify.js} should be imported via this function too. The function \texttt{useMl5} creates two \texttt{html\_dependency} objects, one for the custom code with the message handler and another for the ml5 dependency\index{dependency}. Importantly at the end of the function these are returned in a \texttt{tagList} \textbf{where order matters} as these will be rendered in the order they are listed: first the ml5 dependency then the file containing our custom code.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# R/deps.R}
\CommentTok{#' @export}
\NormalTok{useMl5 <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(}\DataTypeTok{cdn =} \OtherTok{TRUE}\NormalTok{) \{}

  \CommentTok{# internal classify.js file}
\NormalTok{  pkg <-}\StringTok{ }\NormalTok{htmltools}\OperatorTok{::}\KeywordTok{htmlDependency}\NormalTok{(}
    \DataTypeTok{name =} \StringTok{"ml5-pkg"}\NormalTok{,}
    \DataTypeTok{version =} \StringTok{"1.0.0"}\NormalTok{,}
    \DataTypeTok{src =} \StringTok{""}\NormalTok{,}
    \DataTypeTok{script =} \KeywordTok{c}\NormalTok{(}\DataTypeTok{file =} \StringTok{"classify.js"}\NormalTok{),}
    \DataTypeTok{package =} \StringTok{"ml5"}
\NormalTok{  )}

  \CommentTok{# ml5 dependency}
  \ControlFlowTok{if}\NormalTok{(cdn)}
\NormalTok{    ml5 <-}\StringTok{ }\NormalTok{htmltools}\OperatorTok{::}\KeywordTok{htmlDependency}\NormalTok{(}
      \DataTypeTok{name =} \StringTok{"ml5"}\NormalTok{,}
      \DataTypeTok{version =} \StringTok{"0.4.3"}\NormalTok{,}
      \DataTypeTok{src =} \KeywordTok{c}\NormalTok{(}\DataTypeTok{href =} \StringTok{"https://unpkg.com/ml5@0.4.3/dist/"}\NormalTok{),}
      \DataTypeTok{script =} \StringTok{"ml5.min.js"}
\NormalTok{    )}
  \ControlFlowTok{else} 
\NormalTok{    ml5 <-}\StringTok{ }\NormalTok{htmltools}\OperatorTok{::}\KeywordTok{htmlDependency}\NormalTok{(}
      \DataTypeTok{name =} \StringTok{"ml5"}\NormalTok{,}
      \DataTypeTok{version =} \StringTok{"0.4.3"}\NormalTok{,}
      \DataTypeTok{src =} \StringTok{""}\NormalTok{,}
      \DataTypeTok{script =} \KeywordTok{c}\NormalTok{(}\DataTypeTok{file =} \StringTok{"ml5.min.js"}\NormalTok{),}
      \DataTypeTok{package =} \StringTok{"ml5"}
\NormalTok{    )}

\NormalTok{  htmltools}\OperatorTok{::}\KeywordTok{tagList}\NormalTok{(ml5, pkg)}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

\hypertarget{shiny-complete-pkg-trigger}{%
\subsection{Trigger classification}\label{shiny-complete-pkg-trigger}}

There will be a need for a function that sends a message to the front end to trigger the classification. In the application built previously the \texttt{id} of the image to classify was hard-coded this must be changed when building a package.

First, this will give users a much better interface where they may use whatever \texttt{id} suits them. Second, this will allow using the model to classify images that may be placed in different places and bear different ids.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# R/classify.R}
\CommentTok{#' @export}
\NormalTok{classify <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(}
\NormalTok{  id, }
  \DataTypeTok{session =}\NormalTok{ shiny}\OperatorTok{::}\KeywordTok{getDefaultReactiveDomain}\NormalTok{()}
\NormalTok{  )\{}
\NormalTok{    session}\OperatorTok{$}\KeywordTok{sendCustomMessage}\NormalTok{(}\StringTok{"ml5-classify"}\NormalTok{, id)}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

\hypertarget{shiny-complete-pkg-js-code}{%
\subsection{JavaScript code}\label{shiny-complete-pkg-js-code}}

As a quick reminder, the JavaScript should initialise the model and provide a handler for the message \texttt{ml5-classify} that was defined in the previous section. Nothing needs to change with regard to the initialisation of the model. However, there are two things to adapt in the message handler. First, the \texttt{id} of the image to classify is now dynamically defined and passed from the R server; the code should therefore read \texttt{document.getElementById(data)} (where data is passed from the server) instead of \texttt{document.getElementById(\textquotesingle{}birds\textquotesingle{})} as was previously hard-coded in the application.

Second, the application also had hardcoded the input id that was set with the results of the classification (\texttt{input\$classification}). This will no longer work in a package: given the ability to classify multiple images the results of that classification should set different inputs so as not to overwrite one another. In the code below, we therefore create a dynamic input using the id: \texttt{id} + \texttt{\_classification}. Note that one can concatenate string in JavaScript using \texttt{+}, while in R one would have to use the \texttt{paste0} function.

Examples:

\begin{itemize}
\tightlist
\item
  Classify image with \texttt{id\ =\ \textquotesingle{}birds\textquotesingle{}} will return results to \texttt{input\$birds\_classification}
\item
  Classify image with \texttt{id\ =\ \textquotesingle{}things\textquotesingle{}} will return results to \texttt{input\$things\_classification}
\end{itemize}

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{// Initialize the Image Classifier method with MobileNet}
\KeywordTok{const}\NormalTok{ classifier }\OperatorTok{=} \VariableTok{ml5}\NormalTok{.}\AttributeTok{imageClassifier}\NormalTok{(}\StringTok{'MobileNet'}\OperatorTok{,}\NormalTok{ modelLoaded)}\OperatorTok{;}
\CommentTok{// When the model is loaded}
\KeywordTok{function} \AttributeTok{modelLoaded}\NormalTok{() }\OperatorTok{\{}
  \VariableTok{console}\NormalTok{.}\AttributeTok{log}\NormalTok{(}\StringTok{'Model Loaded!'}\NormalTok{)}\OperatorTok{;}
\OperatorTok{\}}

\VariableTok{Shiny}\NormalTok{.}\AttributeTok{addCustomMessageHandler}\NormalTok{(}\StringTok{'classify'}\OperatorTok{,} \KeywordTok{function}\NormalTok{(data)}\OperatorTok{\{}
  \CommentTok{// Classify bird}
  \VariableTok{classifier}\NormalTok{.}\AttributeTok{classify}\NormalTok{(}
    \VariableTok{document}\NormalTok{.}\AttributeTok{getElementById}\NormalTok{(}\StringTok{"bird"}\NormalTok{)}\OperatorTok{,}\NormalTok{ (err}\OperatorTok{,}\NormalTok{ results) }\KeywordTok{=>} \OperatorTok{\{}
      \VariableTok{Shiny}\NormalTok{.}\AttributeTok{setInputValue}\NormalTok{(}\StringTok{"classification:ml5.class"}\OperatorTok{,}\NormalTok{ results)}\OperatorTok{;}
    \OperatorTok{\}}
\NormalTok{  )}\OperatorTok{;}
\OperatorTok{\}}\NormalTok{)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

\hypertarget{shiny-complete-pkg-input-handler}{%
\subsection{Input handler}\label{shiny-complete-pkg-input-handler}}

As mentioned the input handler that transforms the result sent from JavaScript to R into a data.frame can only be registered once. Therefore, placing the code that was written in an R file in the package will not work, or rather will work only once.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# R/handler.R}
\NormalTok{handler <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(data, ...)\{}
\NormalTok{  purrr}\OperatorTok{::}\KeywordTok{map_dfr}\NormalTok{(data, as.data.frame)}
\NormalTok{\}}

\CommentTok{# This will error}
\CommentTok{# register with shiny}
\NormalTok{shiny}\OperatorTok{::}\KeywordTok{registerInputHandler}\NormalTok{(}\StringTok{"ml5.class"}\NormalTok{, handler)}
\end{Highlighting}
\end{Shaded}

When the library is loaded the first time it will work, but all subsequent attempts will fail.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(ml5)}

\CommentTok{#> Loading ml5}

\KeywordTok{library}\NormalTok{(ml5)}

\CommentTok{#> Loading ml5}
\CommentTok{#> Error in shiny::registerInputHandler("ml5.class", handler) : }
\CommentTok{#>   There is already an input handler for type: ml5.class}
\end{Highlighting}
\end{Shaded}

Packages can run functions when they are loaded or attached to an \texttt{.onLoad} function, which is called when the library is loaded in the global environment\index{environment}. The difference between loading and attaching a package can be subtle. In this case, it's probably best to run the function when the package is loaded using \texttt{.onLoad} which the R Packages book describes as:

\begin{quote}
Loading will load code, data, and any DLLs; register S3 and S4 methods; and run the \texttt{.onLoad()} function. After loading, the package is available in memory, but because it's not in the search path, you won't be able to access its components without using \texttt{::}. Confusingly, \texttt{::} will also load a package automatically if it isn't already loaded. It's rare to load a package explicitly, but you can do so with \texttt{requireNamespace()} or \texttt{loadNamespace()}.
\end{quote}

--- \href{https://r-pkgs.org/}{R Packages Book}

This could be used here to ensure the handler is only registered once; calling \texttt{library(packageName)} twice \emph{does not} load the package twice, the second time it runs the function observes that the package is already loaded and thus does not load it again. The \texttt{.onLoad} replacement function may accept \texttt{libname} and \texttt{pkgname} arguments, we simplify the function to using \texttt{...} as we do not need those arguments.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# create handler}
\NormalTok{handler <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(data, ...)\{}
\NormalTok{  purrr}\OperatorTok{::}\KeywordTok{map_dfr}\NormalTok{(data, as.data.frame)}
\NormalTok{\}}

\CommentTok{# register with shiny}
\NormalTok{.onLoad <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(...)\{}
\NormalTok{  shiny}\OperatorTok{::}\KeywordTok{registerInputHandler}\NormalTok{(}\StringTok{"ml5.class"}\NormalTok{, handler)}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

\hypertarget{shiny-complete-pkg-test}{%
\subsection{Test}\label{shiny-complete-pkg-test}}

This is about all that is needed in order to build the package; one can then run \texttt{devtools::document()} to produce the man files and populate the namespace with the exported\index{export} functions then install the package with \texttt{devtools::install()} in order to test it.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(DT)}
\KeywordTok{library}\NormalTok{(ml5)}
\KeywordTok{library}\NormalTok{(shiny)}

\KeywordTok{addResourcePath}\NormalTok{(}\StringTok{"assets"}\NormalTok{, }\StringTok{"assets"}\NormalTok{)}

\NormalTok{ui <-}\StringTok{ }\KeywordTok{fluidPage}\NormalTok{(}
  \KeywordTok{useMl5}\NormalTok{(),}
  \KeywordTok{selectInput}\NormalTok{(}
    \DataTypeTok{inputId =} \StringTok{"selectedBird"}\NormalTok{, }
    \DataTypeTok{label =} \StringTok{"bird"}\NormalTok{,}
    \DataTypeTok{choices =} \KeywordTok{c}\NormalTok{(}\StringTok{"flamingo"}\NormalTok{, }\StringTok{"lorikeet"}\NormalTok{)}
\NormalTok{  ),}
  \KeywordTok{actionButton}\NormalTok{(}\StringTok{"classify"}\NormalTok{, }\StringTok{"Classify"}\NormalTok{),}
  \KeywordTok{uiOutput}\NormalTok{(}\StringTok{"birdDisplay"}\NormalTok{),}
  \KeywordTok{DTOutput}\NormalTok{(}\StringTok{"results"}\NormalTok{)}
\NormalTok{)}

\NormalTok{server <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(input, output, session) \{}

\NormalTok{  output}\OperatorTok{$}\NormalTok{birdDisplay <-}\StringTok{ }\KeywordTok{renderUI}\NormalTok{(\{}
\NormalTok{    path <-}\StringTok{ }\KeywordTok{sprintf}\NormalTok{(}\StringTok{"assets/%s.jpg"}\NormalTok{, input}\OperatorTok{$}\NormalTok{selectedBird)}
\NormalTok{    tags}\OperatorTok{$}\KeywordTok{img}\NormalTok{(}\DataTypeTok{src =}\NormalTok{ path, }\DataTypeTok{id =} \StringTok{"bird"}\NormalTok{)}
\NormalTok{  \})}

  \KeywordTok{observeEvent}\NormalTok{(input}\OperatorTok{$}\NormalTok{classify, \{}
    \KeywordTok{classify}\NormalTok{(}\StringTok{"bird"}\NormalTok{)}
\NormalTok{  \})}

\NormalTok{  output}\OperatorTok{$}\NormalTok{results <-}\StringTok{ }\KeywordTok{renderDT}\NormalTok{(\{}
    \KeywordTok{datatable}\NormalTok{(input}\OperatorTok{$}\NormalTok{bird_classification)}
\NormalTok{  \})}

\NormalTok{\}}

\KeywordTok{shinyApp}\NormalTok{(ui, server)}
\end{Highlighting}
\end{Shaded}

\hypertarget{shiny-tips}{%
\chapter{Tips and Tricks}\label{shiny-tips}}

While previous chapters on working with Shiny made use of external libraries and built packages that brought new functionalities previously not available in Shiny, one does not have to go to this length to take advantage of the learnings contained in those pages. Moreover, there are a few exciting things that have not yet been explored.

\hypertarget{shiny-tips-events}{%
\section{Shiny Events}\label{shiny-tips-events}}

There is a wee bit of documentation tucked away on the \href{https://shiny.rstudio.com/articles/js-events.html}{shiny website} that contains a useful list of events that Shiny fires to notify the developer of interesting things that happen in the application. This includes events that are fired when outputs are being recalculated, when Shiny\index{Shiny} connects, when an element become visible, and more. To demonstrate how to use those events and how handy they can be, we will create a notification which appears to indicate that the server is busy running computations. This could be as fancy as ever, but for simplicity's sake, we limit the demonstration to showing and hiding a gif.

First, we create the directories and necessary files, and to indicate the server is busy. We'll be using a gif that is rather well-known in the R community. Note that we will be using some CSS, hence the \texttt{style.css} file.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{dir.create}\NormalTok{(}\StringTok{"www"}\NormalTok{)}
\KeywordTok{file.create}\NormalTok{(}\StringTok{"www/script.js"}\NormalTok{)}
\KeywordTok{file.create}\NormalTok{(}\StringTok{"www/style.css"}\NormalTok{)}

\CommentTok{# gif}
\NormalTok{gif <-}\StringTok{ }\KeywordTok{paste0}\NormalTok{(}
  \StringTok{"https://github.com/JohnCoene/javascript-for-r/"}\NormalTok{,}
  \StringTok{"raw/master/code/events/www/typing.gif"}
\NormalTok{)}
\KeywordTok{download.file}\NormalTok{(gif, }\StringTok{"www/typing.gif"}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

Then we create an application that draws and redraws a plot at the click of a button. Note that we give the gif an id as we will need to be able to retrieve this element JavaScript-side (to dynamically show and hide it), and an \texttt{id} makes for an ideal selector.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# app.R}
\KeywordTok{library}\NormalTok{(shiny)}

\NormalTok{shiny}\OperatorTok{::}\KeywordTok{addResourcePath}\NormalTok{(}\StringTok{"www"}\NormalTok{, }\StringTok{"www"}\NormalTok{)}

\NormalTok{ui <-}\StringTok{ }\KeywordTok{fluidPage}\NormalTok{(}
  \CommentTok{# import dependencies}
\NormalTok{  tags}\OperatorTok{$}\KeywordTok{head}\NormalTok{(}
\NormalTok{    tags}\OperatorTok{$}\KeywordTok{link}\NormalTok{(}\DataTypeTok{href =} \StringTok{"www/style.css"}\NormalTok{, }\DataTypeTok{rel =} \StringTok{"stylesheet"}\NormalTok{),}
\NormalTok{    tags}\OperatorTok{$}\KeywordTok{script}\NormalTok{(}\DataTypeTok{src =} \StringTok{"www/script.js"}\NormalTok{)}
\NormalTok{  ),}
  \CommentTok{# gif indicator}
\NormalTok{  tags}\OperatorTok{$}\KeywordTok{img}\NormalTok{(}\DataTypeTok{src =} \StringTok{"www/typing.gif"}\NormalTok{, }\DataTypeTok{id =} \StringTok{"loading"}\NormalTok{)}
  \KeywordTok{plotOutput}\NormalTok{(}\StringTok{"plot"}\NormalTok{),}
  \KeywordTok{actionButton}\NormalTok{(}\StringTok{"render"}\NormalTok{, }\StringTok{"render"}\NormalTok{)}
\NormalTok{)}

\NormalTok{server <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(input, output, session) \{}
\NormalTok{  output}\OperatorTok{$}\NormalTok{plot <-}\StringTok{ }\KeywordTok{renderPlot}\NormalTok{(\{}
\NormalTok{    input}\OperatorTok{$}\NormalTok{render }\CommentTok{# redraw on click}

    \CommentTok{# simulate time consuming computations}
    \KeywordTok{Sys.sleep}\NormalTok{(}\DecValTok{2}\NormalTok{) }
    \KeywordTok{plot}\NormalTok{(cars)}
\NormalTok{  \})}
\NormalTok{\}}

\KeywordTok{shinyApp}\NormalTok{(ui, server)}
\end{Highlighting}
\end{Shaded}

The gif should only be visible when the server is busy, unlike now. Whether it is visible will be controlled in JavaScript, so this should be initialised as hidden using CSS. The following code hides the gif with \texttt{visibility:\ hidden}, and repositions it, floating on top of the rest of the content in the top right of the page, the \texttt{z-index} ensures the gif appears on top of other elements.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{/* style.css */}
\PreprocessorTok{#loading}\NormalTok{\{}
  \KeywordTok{top}\NormalTok{: }\DecValTok{20}\DataTypeTok{px}\OperatorTok{;}
  \KeywordTok{right}\NormalTok{: }\DecValTok{20}\DataTypeTok{px}\OperatorTok{;}
  \KeywordTok{height}\NormalTok{: }\DecValTok{200}\DataTypeTok{px}\OperatorTok{;}
  \KeywordTok{z-index}\NormalTok{: }\DecValTok{9999}\OperatorTok{;}
  \KeywordTok{position}\NormalTok{: }\DecValTok{absolute}\OperatorTok{;}
  \KeywordTok{visibility}\NormalTok{: }\DecValTok{hidden}\OperatorTok{;}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

We can then use the Shiny events to dynamically show and hide the gif when the server is busy. Below we observe the event \texttt{shiny:busy} on the entire page (\texttt{document}) when the event is triggered the gif is retrieved using its \texttt{id} and then made visible by changing its CSS \texttt{visibility} property to \texttt{visible}.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{// script.js}
\AttributeTok{$}\NormalTok{(document).}\AttributeTok{on}\NormalTok{(}\StringTok{'shiny:busy'}\OperatorTok{,} \KeywordTok{function}\NormalTok{(event) }\OperatorTok{\{}
  \CommentTok{// retrieve the gif}
  \KeywordTok{var}\NormalTok{ title }\OperatorTok{=} \VariableTok{document}\NormalTok{.}\AttributeTok{getElementById}\NormalTok{(}\StringTok{"loading"}\NormalTok{)}\OperatorTok{;}

  \CommentTok{// make it visible}
  \VariableTok{title}\NormalTok{.}\VariableTok{style}\NormalTok{.}\AttributeTok{visibility} \OperatorTok{=} \StringTok{"visible"}\OperatorTok{;}
\OperatorTok{\}}\NormalTok{)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

We then need to hide the gif when the server goes from busy to idle, using the \texttt{shiny:idle} event we can change the visibility of the gif back to \texttt{hidden}.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{// script.js}
\AttributeTok{$}\NormalTok{(document).}\AttributeTok{on}\NormalTok{(}\StringTok{'shiny:busy'}\OperatorTok{,} \KeywordTok{function}\NormalTok{(event) }\OperatorTok{\{}
  \CommentTok{// retrieve the gif}
  \KeywordTok{var}\NormalTok{ gif }\OperatorTok{=} \VariableTok{document}\NormalTok{.}\AttributeTok{getElementById}\NormalTok{(}\StringTok{"loading"}\NormalTok{)}\OperatorTok{;}

  \CommentTok{// make gif visible}
  \VariableTok{gif}\NormalTok{.}\VariableTok{style}\NormalTok{.}\AttributeTok{visibility} \OperatorTok{=} \StringTok{"visible"}\OperatorTok{;}
\OperatorTok{\}}\NormalTok{)}\OperatorTok{;}

\AttributeTok{$}\NormalTok{(document).}\AttributeTok{on}\NormalTok{(}\StringTok{'shiny:idle'}\OperatorTok{,} \KeywordTok{function}\NormalTok{(event) }\OperatorTok{\{}
  \KeywordTok{var}\NormalTok{ gif }\OperatorTok{=} \VariableTok{document}\NormalTok{.}\AttributeTok{getElementById}\NormalTok{(}\StringTok{"loading"}\NormalTok{)}\OperatorTok{;}

  \CommentTok{// hide gif}
  \VariableTok{gif}\NormalTok{.}\VariableTok{style}\NormalTok{.}\AttributeTok{visibility} \OperatorTok{=} \StringTok{"hidden"}\OperatorTok{;}
\OperatorTok{\}}\NormalTok{)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

The application will then display the gif when the server is busy running computations as in Figure \ref{fig:shiny-events}.

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/shiny-events} 

}

\caption{Shiny with a busy indicator}\label{fig:shiny-events}
\end{figure}

\hypertarget{shiny-tips-table-btn}{%
\section{Table Buttons}\label{shiny-tips-table-btn}}

For instance, using what was learned previously, one can place buttons inside a Shiny\index{Shiny} table and observe server-side, which is clicked. With a basic application that only includes a table to which we ultimately want to add a column containing a button on each row. Here we achieve this by having each button set a different value (e.g., an id) to an input using \texttt{shiny.setInputValue}, but one could very well create different input names for each button.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(DT)}
\KeywordTok{library}\NormalTok{(shiny)}

\NormalTok{ui <-}\StringTok{ }\KeywordTok{fluidPage}\NormalTok{(}
  \KeywordTok{DTOutput}\NormalTok{(}\StringTok{"table"}\NormalTok{)}
\NormalTok{)}

\NormalTok{server <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(input, output) \{}

\NormalTok{  output}\OperatorTok{$}\NormalTok{table <-}\StringTok{ }\KeywordTok{renderDT}\NormalTok{(\{}
    \KeywordTok{datatable}\NormalTok{(}
\NormalTok{      mtcars, }
      \DataTypeTok{escape =} \OtherTok{FALSE}\NormalTok{, }
      \DataTypeTok{selection =} \StringTok{"none"}\NormalTok{, }
      \DataTypeTok{rownames =} \OtherTok{FALSE}\NormalTok{, }
      \DataTypeTok{style =} \StringTok{"bootstrap"}
\NormalTok{    )}
\NormalTok{  \})}

\NormalTok{\}}

\KeywordTok{shinyApp}\NormalTok{(ui, server)}
\end{Highlighting}
\end{Shaded}

Note that in the above we pass some parameters to \texttt{datatable} not all are necessary at the exception of \texttt{escape}, which is set to \texttt{FALSE} as we will ultimately place HTML code the table which should appear rendered rather than show said code as a string.

We start by creating the on-click functions as R character strings for each row of the \texttt{mtcars} dataset. This is the function that will be triggered when buttons are clicked. This should look familiar we use \texttt{Shiny.setInputValue} to define an input named \texttt{click}, which is set to a different value for every row of the table.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(DT)}
\KeywordTok{library}\NormalTok{(shiny)}

\NormalTok{ui <-}\StringTok{ }\KeywordTok{fluidPage}\NormalTok{(}
  \KeywordTok{DTOutput}\NormalTok{(}\StringTok{"table"}\NormalTok{)}
\NormalTok{)}

\NormalTok{server <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(input, output) \{}

\NormalTok{  output}\OperatorTok{$}\NormalTok{table <-}\StringTok{ }\KeywordTok{renderDT}\NormalTok{(\{}
    \CommentTok{# on click function}
\NormalTok{    onclick <-}\StringTok{ }\KeywordTok{sprintf}\NormalTok{(}
      \StringTok{"Shiny.setInputValue('click', '%s')"}\NormalTok{, }
      \KeywordTok{rownames}\NormalTok{(mtcars)}
\NormalTok{    ) }
    
    \KeywordTok{datatable}\NormalTok{(}
\NormalTok{      mtcars, }
      \DataTypeTok{escape =} \OtherTok{FALSE}\NormalTok{, }
      \DataTypeTok{selection =} \StringTok{"none"}\NormalTok{, }
      \DataTypeTok{rownames =} \OtherTok{FALSE}\NormalTok{, }
      \DataTypeTok{style =} \StringTok{"bootstrap"}
\NormalTok{    )}
\NormalTok{  \})}

\NormalTok{\}}

\KeywordTok{shinyApp}\NormalTok{(ui, server)}
\end{Highlighting}
\end{Shaded}

Next, we create the buttons for each row and set the JavaScript functions previously created as the \texttt{onClick} attributes. The JavaScript code passed to the \texttt{onClick} attribute will be executed every time the button is clicked.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(DT)}
\KeywordTok{library}\NormalTok{(shiny)}

\NormalTok{ui <-}\StringTok{ }\KeywordTok{fluidPage}\NormalTok{(}
  \KeywordTok{DTOutput}\NormalTok{(}\StringTok{"table"}\NormalTok{)}
\NormalTok{)}

\NormalTok{server <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(input, output) \{}

\NormalTok{  output}\OperatorTok{$}\NormalTok{table <-}\StringTok{ }\KeywordTok{renderDT}\NormalTok{(\{}
    \CommentTok{# on click function}
\NormalTok{    onclick <-}\StringTok{ }\KeywordTok{sprintf}\NormalTok{(}
      \StringTok{"Shiny.setInputValue('click', '%s')"}\NormalTok{, }
      \KeywordTok{rownames}\NormalTok{(mtcars)}
\NormalTok{    ) }

    \CommentTok{# button with onClick function}
\NormalTok{    button <-}\StringTok{ }\KeywordTok{sprintf}\NormalTok{(}
      \StringTok{"<a class='btn btn-primary' onClick='%s'>Click me</a>"}\NormalTok{,}
\NormalTok{      onclick}
\NormalTok{    )}

\NormalTok{    mtcars}\OperatorTok{$}\NormalTok{button <-}\StringTok{ }\NormalTok{button}
    \KeywordTok{datatable}\NormalTok{(}
\NormalTok{      mtcars, }
      \DataTypeTok{escape =} \OtherTok{FALSE}\NormalTok{, }
      \DataTypeTok{selection =} \StringTok{"none"}\NormalTok{, }
      \DataTypeTok{rownames =} \OtherTok{FALSE}\NormalTok{, }
      \DataTypeTok{style =} \StringTok{"bootstrap"}
\NormalTok{    )}
\NormalTok{  \})}

\NormalTok{\}}

\KeywordTok{shinyApp}\NormalTok{(ui, server)}
\end{Highlighting}
\end{Shaded}

We can then observe the \texttt{click} input and, to demonstrate, render it's value in the UI, see Figure \ref{fig:dt-button} below.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(DT)}
\KeywordTok{library}\NormalTok{(shiny)}

\NormalTok{ui <-}\StringTok{ }\KeywordTok{fluidPage}\NormalTok{(}
  \KeywordTok{br}\NormalTok{(),}
  \KeywordTok{DTOutput}\NormalTok{(}\StringTok{"table"}\NormalTok{),}
  \KeywordTok{strong}\NormalTok{(}\StringTok{"Clicked Model:"}\NormalTok{),}
  \KeywordTok{verbatimTextOutput}\NormalTok{(}\StringTok{"model"}\NormalTok{)}
\NormalTok{)}

\NormalTok{server <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(input, output) \{}

\NormalTok{  output}\OperatorTok{$}\NormalTok{table <-}\StringTok{ }\KeywordTok{renderDT}\NormalTok{(\{}
    \CommentTok{# on click function}
\NormalTok{    onclick <-}\StringTok{ }\KeywordTok{sprintf}\NormalTok{(}
      \StringTok{"Shiny.setInputValue('click', '%s')"}\NormalTok{, }
      \KeywordTok{rownames}\NormalTok{(mtcars)}
\NormalTok{    ) }

    \CommentTok{# button with onClick function}
\NormalTok{    button <-}\StringTok{ }\KeywordTok{sprintf}\NormalTok{(}
      \StringTok{"<a class='btn btn-primary' onClick='%s'>Click me</a>"}\NormalTok{,}
\NormalTok{      onclick}
\NormalTok{    )}

    \CommentTok{# add button to data.frame}
\NormalTok{    mtcars}\OperatorTok{$}\NormalTok{button <-}\StringTok{ }\NormalTok{button}

    \KeywordTok{datatable}\NormalTok{(}
\NormalTok{      mtcars, }
      \DataTypeTok{escape =} \OtherTok{FALSE}\NormalTok{, }
      \DataTypeTok{selection =} \StringTok{"none"}\NormalTok{, }
      \DataTypeTok{rownames =} \OtherTok{FALSE}\NormalTok{, }
      \DataTypeTok{style =} \StringTok{"bootstrap"}
\NormalTok{    )}
\NormalTok{  \})}

\NormalTok{  output}\OperatorTok{$}\NormalTok{model <-}\StringTok{ }\KeywordTok{renderPrint}\NormalTok{(\{}
    \KeywordTok{print}\NormalTok{(input}\OperatorTok{$}\NormalTok{click)}
\NormalTok{  \})}
\NormalTok{\}}

\KeywordTok{shinyApp}\NormalTok{(ui, server)}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/dt-button} 

}

\caption{DT with custom inputs}\label{fig:dt-button}
\end{figure}

\hypertarget{shiny-tips-jQuery}{%
\section{jQuery}\label{shiny-tips-jQuery}}

The Shiny framework itself makes use of and thus imports the \href{https://jquery.com/}{jQuery}\index{jQuery} JavaScript library, a library that provides a convenient API to make many things easier, including animations.

As an example, we could use jQuery's \texttt{show}, \texttt{hide}, or \texttt{toggle} functions to show or hide an HTML element at the press of a button.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{// example of jQuery animation}
\AttributeTok{$}\NormalTok{(}\StringTok{'#id'}\NormalTok{).}\AttributeTok{toggle}\NormalTok{()}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

Because jQuery\index{jQuery} is already imported, there is no need to do so, on the contrary, importing it again will impact load time and might clash with the pre-existing version. Below we create a Shiny application containing a message handler to toggle (show or hide element depending on its state) at the click of a button.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(shiny)}

\NormalTok{ui <-}\StringTok{ }\KeywordTok{fluidPage}\NormalTok{(}
\NormalTok{  tags}\OperatorTok{$}\KeywordTok{head}\NormalTok{(}
\NormalTok{    tags}\OperatorTok{$}\KeywordTok{script}\NormalTok{(}
      \StringTok{"Shiny.addCustomMessageHandler(}
\StringTok{        'jquery-toggle', function(id)\{}
\StringTok{          $('#' + id).toggle(); // id}
\StringTok{      \});"}
\NormalTok{    )}
\NormalTok{  ),}
  \KeywordTok{actionButton}\NormalTok{(}\StringTok{"toggle"}\NormalTok{, }\StringTok{"Toggle text"}\NormalTok{),}
  \KeywordTok{h1}\NormalTok{(}\StringTok{"This text is shown!"}\NormalTok{, }\DataTypeTok{id =} \StringTok{"text"}\NormalTok{)}
\NormalTok{)}

\NormalTok{server <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(input, output, session)\{}

  \KeywordTok{observeEvent}\NormalTok{(input}\OperatorTok{$}\NormalTok{toggle, \{}
\NormalTok{    session}\OperatorTok{$}\KeywordTok{sendCustomMessage}\NormalTok{(}\StringTok{'jquery-toggle'}\NormalTok{, }\StringTok{"text"}\NormalTok{)}
\NormalTok{  \})}

\NormalTok{\}}

\KeywordTok{shinyApp}\NormalTok{(ui, server)}
\end{Highlighting}
\end{Shaded}

Note that jQuery\index{jQuery} takes a selector so one could very well use a class to hide and show multiple elements (with said class) at once.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(shiny)}

\NormalTok{ui <-}\StringTok{ }\KeywordTok{fluidPage}\NormalTok{(}
\NormalTok{  tags}\OperatorTok{$}\KeywordTok{head}\NormalTok{(}
\NormalTok{    tags}\OperatorTok{$}\KeywordTok{script}\NormalTok{(}
      \StringTok{"Shiny.addCustomMessageHandler(}
\StringTok{        'jquery-toggle', function(selector)\{}
\StringTok{          $(selector).toggle();}
\StringTok{      \});"}
\NormalTok{    )}
\NormalTok{  ),}
  \KeywordTok{actionButton}\NormalTok{(}\StringTok{"toggle"}\NormalTok{, }\StringTok{"Toggle text"}\NormalTok{),}
  \KeywordTok{h1}\NormalTok{(}\StringTok{"This text is shown!"}\NormalTok{, }\DataTypeTok{class =} \StringTok{"to-toggle"}\NormalTok{),}
  \KeywordTok{actionButton}\NormalTok{(}
    \StringTok{"btn"}\NormalTok{, }\StringTok{"Another visible button"}\NormalTok{, }\DataTypeTok{class =} \StringTok{"to-toggle"}
\NormalTok{  )}
\NormalTok{)}

\NormalTok{server <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(input, output, session)\{}

  \KeywordTok{observeEvent}\NormalTok{(input}\OperatorTok{$}\NormalTok{toggle, \{}
\NormalTok{    session}\OperatorTok{$}\KeywordTok{sendCustomMessage}\NormalTok{(}\StringTok{'jquery-toggle'}\NormalTok{, }\StringTok{".to-toggle"}\NormalTok{)}
\NormalTok{  \})}

\NormalTok{\}}

\KeywordTok{shinyApp}\NormalTok{(ui, server)}
\end{Highlighting}
\end{Shaded}

This is something where, again, R is leveraged in order to make it easier on the Shiny developer, but it must be said that it suffers from some inefficiency: the message travels from the browser (button click) to the R server, where it is sent back to the browser and triggers \texttt{toggle}. It could indeed very well be rewritten in JavaScript entirely. This is, however, outside the scope of this book.

\hypertarget{shiny-output}{%
\chapter{Custom Outputs}\label{shiny-output}}

In this chapter, we create a custom Shiny output; in practical terms, this creates custom \texttt{render*} and \texttt{*Output} functions to use in Shiny. This will be demonstrated by creating something akin to the \texttt{valueBox} available in the shinydashboard \citep{R-shinydashboard} package. While similar to what shinydashboard provides, this box will 1) be fully customisable and 2) available in any Shiny application 3) have additional functionalities.

The \texttt{valueBox} equivalent we shall build in this chapter is named ``boxxy,'' and allows creating simple but colourful value boxes with animated numbers (by counting up to it) using \href{https://github.com/inorganik/countUp.js}{countUp.js}.

Figure \ref{fig:boxxy-example} demonstrates what will be built in this chapter.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(shiny)}

\NormalTok{ui <-}\StringTok{ }\KeywordTok{fluidPage}\NormalTok{(}
  \KeywordTok{boxxyOutput}\NormalTok{(}\StringTok{"countries"}\NormalTok{)}
\NormalTok{)}

\NormalTok{server <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(input, output)\{}
\NormalTok{  output}\OperatorTok{$}\NormalTok{countries <-}\StringTok{ }\KeywordTok{renderBoxxy}\NormalTok{(\{}
    \KeywordTok{boxxy}\NormalTok{(}\StringTok{"Countries"}\NormalTok{, }\DecValTok{95}\NormalTok{)}
\NormalTok{  \})}
\NormalTok{\}}

\KeywordTok{shinyApp}\NormalTok{(ui, server)}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/boxxy-example} 

}

\caption{Custom output example}\label{fig:boxxy-example}
\end{figure}

\hypertarget{shiny-output-inner-workings}{%
\section{Inner-workings}\label{shiny-output-inner-workings}}

At the core, this consists in creating three functions: \texttt{boxxy}, \texttt{renderBoxxy}, and \texttt{boxxyOutput} (analogous to \texttt{plot}, \texttt{renderPlot}, \texttt{plotOutput}), which are linked by an ``output binding'' in JavaScript.

The first function, \texttt{boxxy} will accept arguments that help define what is in the box. This function is generally useful to preprocess any of the arguments that are meant to produce the custom output. The \texttt{boxxyOutput} function essentially creates the scaffold\index{scaffold} of the HTML output (e.g.: \texttt{\textless{}div\textgreater{}}), as well as the dependencies\index{dependency}. The \texttt{render*} function is perhaps more peculiar: it should accept an expression and return a function.

Previous work with Shiny and JavaScript covered in this book had no dedicated ``output'' elements that were placed in the Shiny UI. Therefore, one had to use a function solely dedicated to importing the dependencies (e.g.: \texttt{usejBox}). However, since this is not the case here, the dependencies\index{dependency} can be attached together with the output.

Finally, the two R functions are ``bound'' JavaScript-side with an ``output binding'' that renders the data from the \texttt{render*} function with its \texttt{*output}.

\hypertarget{shiny-output-setup}{%
\section{Setup}\label{shiny-output-setup}}

The custom output will be part of a Shiny application, let us thus create the basic skeleton of an application and download the dependencies. Create a project in RStudio\index{RStudio} or an empty directory, then:

\begin{enumerate}
\def\labelenumi{\arabic{enumi}.}
\tightlist
\item
  Create an \texttt{app.R} file that will hold the code for the application and \texttt{boxxy}, \texttt{boxxyOutput}, and \texttt{renderBoxxy} functions.
\item
  Create an \texttt{assets}\index{asset} directory that will contain the CSS and JavaScript files.
\item
  Download the countUp.js dependency\index{dependency}.
\item
  Create a \texttt{binding.js} JavaScript file for the JavaScript binding within the previously created \texttt{assets} directory.
\item
  Create a \texttt{styles.css} file in the \texttt{assets}\index{asset} directory.
\end{enumerate}

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# application file}
\KeywordTok{file.create}\NormalTok{(}\StringTok{"app.R"}\NormalTok{)}

\CommentTok{# static file directory}
\KeywordTok{dir.create}\NormalTok{(}\StringTok{"assets"}\NormalTok{)}

\CommentTok{# countup dependency}
\NormalTok{url <-}\StringTok{ }\KeywordTok{paste0}\NormalTok{(}
  \StringTok{"https://cdn.jsdelivr.net/npm/"}\NormalTok{,}
  \StringTok{"countup@1.8.2/countUp.js"}
\NormalTok{)}

\KeywordTok{download.file}\NormalTok{(url, }\StringTok{"assets/countup.js"}\NormalTok{)}

\CommentTok{# create binding file}
\KeywordTok{file.create}\NormalTok{(}\StringTok{"assets/binding.js"}\NormalTok{)}

\CommentTok{# CSS file}
\KeywordTok{file.create}\NormalTok{(}\StringTok{"assets/styles.css"}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

This should produce the following directory structure.

\begin{verbatim}
.
├── app.R
└── assets
    ├── binding.js
    ├── countup.js
    └── styles.css
\end{verbatim}

\hypertarget{shiny-output-r-fun}{%
\section{Output R Function}\label{shiny-output-r-fun}}

The \texttt{boxxy} function takes three arguments: a \texttt{title}, a \texttt{value} that will be animated, and the background \texttt{color} to use for the box. The function, at this stage at least, does not preprocess the arguments and returns them as a named \texttt{list}.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# app.R}
\KeywordTok{library}\NormalTok{(shiny)}

\NormalTok{boxxy <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(title, value, }\DataTypeTok{color =} \StringTok{"#ef476f"}\NormalTok{)\{}
  \KeywordTok{list}\NormalTok{(}\DataTypeTok{title =}\NormalTok{ title, }\DataTypeTok{value =}\NormalTok{ value, }\DataTypeTok{color =}\NormalTok{ color)}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

\hypertarget{shiny-output-html}{%
\section{Generate Output HTML}\label{shiny-output-html}}

The \texttt{boxxyOutput} function, like all such functions (\texttt{plotOutput}, \texttt{uiOutput}, etc.) takes an \texttt{id}. This function should return an HTML tag that bears an \texttt{id}, or a \texttt{data-input-id} attribute (more on that later) and a \texttt{class}. The \texttt{id} is to be defined by the user of the function in Shiny just like any other such outputs. For instance, \texttt{plotOutput} creates a \texttt{\textless{}div\textgreater{}}, the \texttt{id} of which is actually the \texttt{id} used in the \texttt{plotOutput} function.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# the id is used as id to the element}
\NormalTok{shiny}\OperatorTok{::}\KeywordTok{plotOutput}\NormalTok{(}\DataTypeTok{id =} \StringTok{"myPlotId"}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{<div} 
\OtherTok{  id=}\StringTok{"myPlotId"} 
\OtherTok{  class=}\StringTok{"shiny-plot-output"} 
\OtherTok{  style=}\StringTok{"width: 100% ; height: 400px"}\KeywordTok{>}
\KeywordTok{</div>}
\end{Highlighting}
\end{Shaded}

The \texttt{class} is used JavaScript-side to ``find'' the outputs in the DOM\index{DOM} and generate the output. The function \texttt{boxxyOutput} could thus be as shown, the \texttt{id} is passed along to the \texttt{\textless{}div\textgreater{}}, which is created with a \texttt{boxxy} class that will be used in the output binding to find that element and generate the output within that very \texttt{\textless{}div\textgreater{}} using data that will be passed from the server.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{boxxyOutput <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(id)\{}
  \CommentTok{# the HTML output}
\NormalTok{  shiny}\OperatorTok{::}\NormalTok{tags}\OperatorTok{$}\KeywordTok{div}\NormalTok{(}
    \DataTypeTok{id =}\NormalTok{ id, }\DataTypeTok{class =} \StringTok{"boxxy"}
\NormalTok{  )}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

\begin{rmdnote}
Make sure you use unique class names so they are not accidentally
overridden by the user.
\end{rmdnote}

As shown, the box should include a title and an animated value. These could be generated entirely in JavaScript, but it's actually easier to create placeholders with htmltools tags. We generate dynamic ids for those so they can easily be referenced later on in JavaScript: \texttt{id-boxxy-value} for the value and \texttt{id-boxxy-title} for the title.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{boxxyOutput <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(id)\{}
  \CommentTok{# the HTML output}
\NormalTok{  shiny}\OperatorTok{::}\NormalTok{tags}\OperatorTok{$}\KeywordTok{div}\NormalTok{(}
    \DataTypeTok{id =}\NormalTok{ id, }\DataTypeTok{class =} \StringTok{"boxxy"}\NormalTok{,}
    \KeywordTok{h1}\NormalTok{(}
      \DataTypeTok{id =} \KeywordTok{sprintf}\NormalTok{(}\StringTok{"%s-boxxy-value"}\NormalTok{, id), }
      \DataTypeTok{class =} \StringTok{"boxxy-value"}
\NormalTok{    ),}
    \KeywordTok{p}\NormalTok{(}
      \DataTypeTok{id =} \KeywordTok{sprintf}\NormalTok{(}\StringTok{"%s-boxxy-title"}\NormalTok{, id), }
      \DataTypeTok{class =} \StringTok{"boxxy-title"}
\NormalTok{    )}
\NormalTok{  )}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

Finally, we also used classes in the output so every element it comprises can be styled with ease.

\begin{Shaded}
\begin{Highlighting}[]
\FunctionTok{.boxxy}\NormalTok{\{}
  \KeywordTok{text-align}\NormalTok{: }\DecValTok{center}\OperatorTok{;}
  \KeywordTok{border-left}\NormalTok{: }\DecValTok{6}\DataTypeTok{px} \DecValTok{solid} \ConstantTok{#073b4c}\OperatorTok{;}
  \KeywordTok{padding}\NormalTok{: }\DecValTok{1}\DataTypeTok{em}\OperatorTok{;}
\NormalTok{\}}

\FunctionTok{.boxxy-title}\NormalTok{\{}
  \KeywordTok{text-transform}\NormalTok{: }\DecValTok{uppercase}\OperatorTok{;}
\NormalTok{\}}

\FunctionTok{.boxxy-value}\NormalTok{\{}
  \KeywordTok{font-size}\NormalTok{: }\DecValTok{3}\DataTypeTok{em}\OperatorTok{;}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

In some previous examples we created a function decicated to importing dependencies in the Shiny UI but in this case they can piggyback on the \texttt{boxxyOutput} function. This works using the htmltools package. The function \texttt{htmltools::htmlDependency} is used to create a dependency\index{dependency} that is then attached with \texttt{htmltools::attachDependencies}. While the former creates an object that Shiny can understand and translate into \texttt{\textless{}script\textgreater{}} or \texttt{\textless{}style\textgreater{}} tags, the former attaches them to the output object and ensures dependencies are not imported multiple times (e.g.: when \texttt{boxxyOutput} is used more than once).

Notice the use of \texttt{normalizePath} to retrieve the full path to the \texttt{assets}\index{asset} directory as this will not work with a relative path (e.g.: \texttt{./assets}). The dependencies\index{dependency} consist of the three files previously created and necessary to generate the output: \texttt{countup.js}, the dependency that was downloaded, as well as \texttt{binding.js} and \texttt{styles.css}.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{boxxyOutput <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(id)\{}
\NormalTok{  el <-}\StringTok{ }\NormalTok{tags}\OperatorTok{$}\KeywordTok{div}\NormalTok{(}
    \DataTypeTok{id =}\NormalTok{ id, }\DataTypeTok{class =} \StringTok{"boxxy"}\NormalTok{,}
    \KeywordTok{h1}\NormalTok{(}
      \DataTypeTok{id =} \KeywordTok{sprintf}\NormalTok{(}\StringTok{"%s-boxxy-counter"}\NormalTok{, id), }
      \DataTypeTok{class =} \StringTok{"boxxy-value"}
\NormalTok{    ),}
    \KeywordTok{p}\NormalTok{(}
      \DataTypeTok{id =} \KeywordTok{sprintf}\NormalTok{(}\StringTok{"%s-boxxy-title"}\NormalTok{, id), }
      \DataTypeTok{class =} \StringTok{"boxxy-title"}
\NormalTok{    )}
\NormalTok{  )}

  \CommentTok{# get full path}
\NormalTok{  path <-}\StringTok{ }\KeywordTok{normalizePath}\NormalTok{(}\StringTok{"assets"}\NormalTok{)}

\NormalTok{  deps <-}\StringTok{ }\KeywordTok{list}\NormalTok{(}
\NormalTok{    htmltools}\OperatorTok{::}\KeywordTok{htmlDependency}\NormalTok{(}
      \DataTypeTok{name =} \StringTok{"boxxy"}\NormalTok{,}
      \DataTypeTok{version =} \StringTok{"1.0.0"}\NormalTok{,}
      \DataTypeTok{src =} \KeywordTok{c}\NormalTok{(}\DataTypeTok{file =}\NormalTok{ path),}
      \DataTypeTok{script =} \KeywordTok{c}\NormalTok{(}\StringTok{"countup.js"}\NormalTok{, }\StringTok{"binding.js"}\NormalTok{),}
      \DataTypeTok{stylesheet =} \StringTok{"styles.css"}
\NormalTok{    )}
\NormalTok{  )}

\NormalTok{  htmltools}\OperatorTok{::}\KeywordTok{attachDependencies}\NormalTok{(el, deps)}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

Running the function reveals the HTML\index{HTML} it generates at the exception of the dependencies\index{dependency} which htmltools does not print to the console.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{boxxyOutput}\NormalTok{(}\StringTok{"myID"}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{<div}\OtherTok{ id=}\StringTok{"myID"}\OtherTok{ class=}\StringTok{"boxxy"}\KeywordTok{>}
  \KeywordTok{<h1}\OtherTok{ id=}\StringTok{"myID-boxxy-counter"}\OtherTok{ class=}\StringTok{"boxxy-value"}\KeywordTok{></h1>}
  \KeywordTok{<p}\OtherTok{ id=}\StringTok{"myID-boxxy-title"}\OtherTok{ class=}\StringTok{"boxxy-title"}\KeywordTok{></p>}
\KeywordTok{</div>}
\end{Highlighting}
\end{Shaded}

\hypertarget{shiny-output-renderer}{%
\section{Output Renderer}\label{shiny-output-renderer}}

The function \texttt{renderBoxxy} should accept an expression, like other such \texttt{render*} functions. For instance, in the example below the \texttt{renderPlot} function does accept an expression that uses, amongst other functions, \texttt{plot}.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{output}\OperatorTok{$}\NormalTok{myPlot <-}\StringTok{ }\KeywordTok{renderPlot}\NormalTok{(\{}
  \CommentTok{# this is an expression}
\NormalTok{  cars }\OperatorTok{%>%}\StringTok{ }
\StringTok{    }\KeywordTok{head}\NormalTok{() }\OperatorTok{%>%}\StringTok{ }
\StringTok{    }\KeywordTok{plot}\NormalTok{()}
\NormalTok{\})}
\end{Highlighting}
\end{Shaded}

The function \texttt{renderBoxxy} takes an expression and other arguments that are passed to \texttt{shiny::exprToFunction}. This does pretty much what it says on the tin: it returns a function from an expression (unless that expression is a function, in which case it returns the expression). This function must be further wrapped in another as render functions must return functions.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{renderBoxxy <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(expr, }\DataTypeTok{env =} \KeywordTok{parent.frame}\NormalTok{(), }
  \DataTypeTok{quoted =} \OtherTok{FALSE}\NormalTok{) \{}
  \CommentTok{# Convert the expression + environment into a function}
\NormalTok{  func <-}\StringTok{ }\NormalTok{shiny}\OperatorTok{::}\KeywordTok{exprToFunction}\NormalTok{(expr, env, quoted)}

  \ControlFlowTok{function}\NormalTok{()\{}
    \KeywordTok{func}\NormalTok{()}
\NormalTok{  \}}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

\hypertarget{shiny-output-binding}{%
\section{JavaScript Output Binding}\label{shiny-output-binding}}

Here we create an ``output binding.'' It tells Shiny how to find the component and how to interact with it. An output binding is initialised from \texttt{Shiny.OutputBinding}. Below we initialise a new binding.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{// custom.js}
\KeywordTok{var}\NormalTok{ boxxyBinding }\OperatorTok{=} \KeywordTok{new} \VariableTok{Shiny}\NormalTok{.}\AttributeTok{OutputBinding}\NormalTok{()}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

Then, this must be ``extended'' by specifying a number of methods, an essential one being \texttt{find}. It is used to look for the output HTML element in the document (\texttt{scope}), and to return them as an array (\texttt{HTMLcollection}). Other methods all take an \texttt{el} argument; that value will always be an element that was returned from \texttt{find}. A very straightforward way to accomplish this is to use jQuery's\index{jQuery} find method to identify elements with the \texttt{boxxy} class used in \texttt{boxxyOutput}. You are by no means forced to use a CSS class to identify the elements, but there is no reason not to.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{// custom.js}
\KeywordTok{var}\NormalTok{ boxxyBinding }\OperatorTok{=} \KeywordTok{new} \VariableTok{Shiny}\NormalTok{.}\AttributeTok{OutputBinding}\NormalTok{()}\OperatorTok{;}

\VariableTok{$}\NormalTok{.}\AttributeTok{extend}\NormalTok{(boxxyBinding}\OperatorTok{,} \OperatorTok{\{}
  \DataTypeTok{find}\OperatorTok{:} \KeywordTok{function}\NormalTok{(scope) }\OperatorTok{\{}
    \ControlFlowTok{return} \AttributeTok{$}\NormalTok{(scope).}\AttributeTok{find}\NormalTok{(}\StringTok{".boxxy"}\NormalTok{)}\OperatorTok{;}
  \OperatorTok{\}}
\OperatorTok{\}}\NormalTok{)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

One might then want to use the \texttt{getId} method, which returns the \texttt{id} of the element, by default, as can be seen in the \href{https://github.com/rstudio/shiny/blob/master/srcjs/output_binding.js}{source code} (below), the binding returns the id as the \texttt{data-input-id} attribute, and if that is false it returns the element's \texttt{id}.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{// getId default}
\KeywordTok{this}\NormalTok{.}\AttributeTok{getId} \OperatorTok{=} \KeywordTok{function}\NormalTok{(el) }\OperatorTok{\{}
  \ControlFlowTok{return}\NormalTok{ el[}\StringTok{'data-input-id'}\NormalTok{] }\OperatorTok{||} \VariableTok{el}\NormalTok{.}\AttributeTok{id}\OperatorTok{;}
\OperatorTok{\}}
\end{Highlighting}
\end{Shaded}

Since boxxy uses the element id, the default will work, and this can be skipped entirely.

Next, one needs to implement the \texttt{renderValue} function, which is the same function that generates the output based on data used in \texttt{boxxy} and sent to the front end with \texttt{renderBoxxy}. The \texttt{renderValue} method accepts two arguments: first \texttt{el}, the element where the output should be generated; this is effectively the output of \texttt{boxxyOutput}, which the binding found using \texttt{find}. The second argument is \texttt{data} which is the data, passed to \texttt{boxxy} and serialised\index{serialise} via \texttt{renderBoxxy}.

\begin{rmdnote}
The \texttt{renderValue} is in effect very similar if not identical to
the JavaScript function of the same name involved in creating
htmlwidgets.
\end{rmdnote}

\hypertarget{shiny-output-boxxy-title}{%
\subsection{Boxxy Title}\label{shiny-output-boxxy-title}}

Let us now tackle the first of the three core aspects of the boxxy output: the title. The \texttt{title} should be placed in the previously-created placeholder which bears the \texttt{id-boxxy-title}, precisely as was done with htmlwidgets previously. We insert title (\texttt{data.title}) in the element with \texttt{innerText}. The dynamically generated id for the title is built in the same way it is in R, by concatenating the \texttt{id} with \texttt{-boxxy-title}

\begin{itemize}
\tightlist
\item
  In R \texttt{sprintf("\%s-boxxy-title",\ id)}
\item
  In JavaScript \texttt{el.id\ +\ \textquotesingle{}-boxxy-title\textquotesingle{}}
\end{itemize}

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{var}\NormalTok{ boxxyBinding }\OperatorTok{=} \KeywordTok{new} \VariableTok{Shiny}\NormalTok{.}\AttributeTok{OutputBinding}\NormalTok{()}\OperatorTok{;}

\VariableTok{$}\NormalTok{.}\AttributeTok{extend}\NormalTok{(boxxyBinding}\OperatorTok{,} \OperatorTok{\{}
  \DataTypeTok{find}\OperatorTok{:} \KeywordTok{function}\NormalTok{(scope) }\OperatorTok{\{}
    \ControlFlowTok{return} \AttributeTok{$}\NormalTok{(scope).}\AttributeTok{find}\NormalTok{(}\StringTok{".boxxy"}\NormalTok{)}\OperatorTok{;}
  \OperatorTok{\},}
  \DataTypeTok{renderValue}\OperatorTok{:} \KeywordTok{function}\NormalTok{(el}\OperatorTok{,}\NormalTok{ data) }\OperatorTok{\{}

    \CommentTok{// insert the title}
    \KeywordTok{let}\NormalTok{ title_id }\OperatorTok{=} \VariableTok{el}\NormalTok{.}\AttributeTok{id} \OperatorTok{+} \StringTok{'-boxxy-title'}\OperatorTok{;}
    \VariableTok{document}\NormalTok{.}\AttributeTok{getElementById}\NormalTok{(title_id).}\AttributeTok{innerText} \OperatorTok{=} \VariableTok{data}\NormalTok{.}\AttributeTok{title}
  \OperatorTok{\}}
\OperatorTok{\}}\NormalTok{)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

\hypertarget{shiny-output-boxxy-value}{%
\subsection{Boxxy Value}\label{shiny-output-boxxy-value}}

Though the custom output could be limited to a static value generated in a fashion similar to how the title is placed, we opted for a more fancy animated value using countUp.js.

Initialise a new counter, specify the id of the element, where it should be created as first argument, as second argument the starting value from which the counter should start, and finally the value to count up to. Note that there is a fourth argument to pass a JSON of options, which we do not use here.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{// place counter in elementId}
\CommentTok{// start at 0 and count up to 123}
\KeywordTok{const}\NormalTok{ counter }\OperatorTok{=} \KeywordTok{new} \AttributeTok{CountUp}\NormalTok{(}\StringTok{'elementId'}\OperatorTok{,} \DecValTok{0}\OperatorTok{,} \DecValTok{123}\NormalTok{)}\OperatorTok{;}
\VariableTok{counter}\NormalTok{.}\AttributeTok{start}\NormalTok{()}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

The counter has to be generated in the \texttt{\textless{}h1\textgreater{}} placeholder bearing the \texttt{id-boxxy-value}, while the value to count up to is stored in \texttt{data.value} meaning the counter can be initialised with \texttt{new\ CountUp(el.id\ +\ \textquotesingle{}-boxxy-value\textquotesingle{},\ 0,\ data.value);}.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{var}\NormalTok{ boxxyBinding }\OperatorTok{=} \KeywordTok{new} \VariableTok{Shiny}\NormalTok{.}\AttributeTok{OutputBinding}\NormalTok{()}\OperatorTok{;}

\VariableTok{$}\NormalTok{.}\AttributeTok{extend}\NormalTok{(boxxyBinding}\OperatorTok{,} \OperatorTok{\{}
  \DataTypeTok{find}\OperatorTok{:} \KeywordTok{function}\NormalTok{(scope) }\OperatorTok{\{}
    \ControlFlowTok{return} \AttributeTok{$}\NormalTok{(scope).}\AttributeTok{find}\NormalTok{(}\StringTok{".boxxy"}\NormalTok{)}\OperatorTok{;}
  \OperatorTok{\},}
  \DataTypeTok{renderValue}\OperatorTok{:} \KeywordTok{function}\NormalTok{(el}\OperatorTok{,}\NormalTok{ data) }\OperatorTok{\{}

    \CommentTok{// insert the title}
    \KeywordTok{let}\NormalTok{ title_id }\OperatorTok{=} \VariableTok{el}\NormalTok{.}\AttributeTok{id} \OperatorTok{+} \StringTok{'-boxxy-title'}\OperatorTok{;}
    \VariableTok{document}\NormalTok{.}\AttributeTok{getElementById}\NormalTok{(title_id).}\AttributeTok{innerText} \OperatorTok{=} \VariableTok{data}\NormalTok{.}\AttributeTok{title}

    \CommentTok{// counter start at 0}
    \KeywordTok{let}\NormalTok{ counter_id }\OperatorTok{=} \VariableTok{el}\NormalTok{.}\AttributeTok{id} \OperatorTok{+} \StringTok{'-boxxy-value'}\OperatorTok{;}
    \KeywordTok{var}\NormalTok{ counter }\OperatorTok{=} \KeywordTok{new} \AttributeTok{CountUp}\NormalTok{(counter_id}\OperatorTok{,} \DecValTok{0}\OperatorTok{,} \VariableTok{data}\NormalTok{.}\AttributeTok{value}\NormalTok{)}\OperatorTok{;}
    \VariableTok{counter}\NormalTok{.}\AttributeTok{start}\NormalTok{()}\OperatorTok{;}
  \OperatorTok{\}}
\OperatorTok{\}}\NormalTok{)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

\hypertarget{shiny-output-boxxy-bg-color}{%
\subsection{Boxxy Background Color}\label{shiny-output-boxxy-bg-color}}

Then we can set the background colour that was passed to \texttt{boxxy} (\texttt{data.color}).

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{var}\NormalTok{ boxxyBinding }\OperatorTok{=} \KeywordTok{new} \VariableTok{Shiny}\NormalTok{.}\AttributeTok{OutputBinding}\NormalTok{()}\OperatorTok{;}

\VariableTok{$}\NormalTok{.}\AttributeTok{extend}\NormalTok{(boxxyBinding}\OperatorTok{,} \OperatorTok{\{}
  \DataTypeTok{find}\OperatorTok{:} \KeywordTok{function}\NormalTok{(scope) }\OperatorTok{\{}
    \ControlFlowTok{return} \AttributeTok{$}\NormalTok{(scope).}\AttributeTok{find}\NormalTok{(}\StringTok{".boxxy"}\NormalTok{)}\OperatorTok{;}
  \OperatorTok{\},}
  \DataTypeTok{renderValue}\OperatorTok{:} \KeywordTok{function}\NormalTok{(el}\OperatorTok{,}\NormalTok{ data) }\OperatorTok{\{}

    \CommentTok{// insert the title}
    \KeywordTok{let}\NormalTok{ title_id }\OperatorTok{=} \VariableTok{el}\NormalTok{.}\AttributeTok{id} \OperatorTok{+} \StringTok{'-boxxy-title'}\OperatorTok{;}
    \VariableTok{document}\NormalTok{.}\AttributeTok{getElementById}\NormalTok{(title_id).}\AttributeTok{innerText} \OperatorTok{=} \VariableTok{data}\NormalTok{.}\AttributeTok{title}

    \CommentTok{// counter start at 0}
    \KeywordTok{let}\NormalTok{ counter_id }\OperatorTok{=} \VariableTok{el}\NormalTok{.}\AttributeTok{id} \OperatorTok{+} \StringTok{'-boxxy-value'}\OperatorTok{;}
    \KeywordTok{var}\NormalTok{ counter }\OperatorTok{=} \KeywordTok{new} \AttributeTok{CountUp}\NormalTok{(counter_id}\OperatorTok{,} \DecValTok{0}\OperatorTok{,} \VariableTok{data}\NormalTok{.}\AttributeTok{value}\NormalTok{)}\OperatorTok{;}
    \VariableTok{counter}\NormalTok{.}\AttributeTok{start}\NormalTok{()}\OperatorTok{;}

    \CommentTok{// background color }
    \VariableTok{el}\NormalTok{.}\VariableTok{style}\NormalTok{.}\AttributeTok{backgroundColor} \OperatorTok{=} \VariableTok{data}\NormalTok{.}\AttributeTok{color}\OperatorTok{;}
  \OperatorTok{\}}
\OperatorTok{\}}\NormalTok{)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

\hypertarget{shiny-output-register}{%
\subsection{Register the Output Binding}\label{shiny-output-register}}

Finally, the output binding must be registered with Shiny. Note that it uses a unique string identifier. The \href{https://shiny.rstudio.com/articles/building-outputs.html}{documentation} states:

\begin{quote}
At the moment it is unused but future features may depend on it.
\end{quote}

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{var}\NormalTok{ boxxyBinding }\OperatorTok{=} \KeywordTok{new} \VariableTok{Shiny}\NormalTok{.}\AttributeTok{OutputBinding}\NormalTok{()}\OperatorTok{;}

\VariableTok{$}\NormalTok{.}\AttributeTok{extend}\NormalTok{(boxxyBinding}\OperatorTok{,} \OperatorTok{\{}
  \DataTypeTok{find}\OperatorTok{:} \KeywordTok{function}\NormalTok{(scope) }\OperatorTok{\{}
    \ControlFlowTok{return} \AttributeTok{$}\NormalTok{(scope).}\AttributeTok{find}\NormalTok{(}\StringTok{".boxxy"}\NormalTok{)}\OperatorTok{;}
  \OperatorTok{\},}
  \DataTypeTok{renderValue}\OperatorTok{:} \KeywordTok{function}\NormalTok{(el}\OperatorTok{,}\NormalTok{ data) }\OperatorTok{\{}

    \CommentTok{// insert the title}
    \KeywordTok{let}\NormalTok{ title_id }\OperatorTok{=} \VariableTok{el}\NormalTok{.}\AttributeTok{id} \OperatorTok{+} \StringTok{'-boxxy-title'}\OperatorTok{;}
    \VariableTok{document}\NormalTok{.}\AttributeTok{getElementById}\NormalTok{(title_id).}\AttributeTok{innerText} \OperatorTok{=} \VariableTok{data}\NormalTok{.}\AttributeTok{title}

    \CommentTok{// counter start at 0}
    \KeywordTok{let}\NormalTok{ counter_id }\OperatorTok{=} \VariableTok{el}\NormalTok{.}\AttributeTok{id} \OperatorTok{+} \StringTok{'-boxxy-value'}\OperatorTok{;}
    \KeywordTok{var}\NormalTok{ counter }\OperatorTok{=} \KeywordTok{new} \AttributeTok{CountUp}\NormalTok{(counter_id}\OperatorTok{,} \DecValTok{0}\OperatorTok{,} \VariableTok{data}\NormalTok{.}\AttributeTok{value}\NormalTok{)}\OperatorTok{;}
    \VariableTok{counter}\NormalTok{.}\AttributeTok{start}\NormalTok{()}\OperatorTok{;}

    \CommentTok{// background color }
    \VariableTok{el}\NormalTok{.}\VariableTok{style}\NormalTok{.}\AttributeTok{backgroundColor} \OperatorTok{=} \VariableTok{data}\NormalTok{.}\AttributeTok{color}\OperatorTok{;}
  \OperatorTok{\}}
\OperatorTok{\}}\NormalTok{)}\OperatorTok{;}

\CommentTok{// register}
\VariableTok{Shiny}\NormalTok{.}\VariableTok{outputBindings}\NormalTok{.}\AttributeTok{register}\NormalTok{(boxxyBinding}\OperatorTok{,} \StringTok{"john.boxxy"}\NormalTok{)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

Ensure that string uniquely identifies the binding to avoid future clash with other such bindings.

\hypertarget{shiny-output-usage}{%
\section{Boxxy Usage}\label{shiny-output-usage}}

With all of this in place, one can use boxxy in a Shiny application (Figure \ref{fig:boxxy-custom}).

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(shiny)}

\NormalTok{boxxy <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(title, value, }\DataTypeTok{color =} \StringTok{"black"}\NormalTok{)\{}
  \KeywordTok{list}\NormalTok{(}\DataTypeTok{title =}\NormalTok{ title, }\DataTypeTok{value =}\NormalTok{ value, }\DataTypeTok{color =}\NormalTok{ color)}
\NormalTok{\}}

\NormalTok{boxxyOutput <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(id)\{}
\NormalTok{  el <-}\StringTok{ }\NormalTok{shiny}\OperatorTok{::}\NormalTok{tags}\OperatorTok{$}\KeywordTok{div}\NormalTok{(}
    \DataTypeTok{id =}\NormalTok{ id, }\DataTypeTok{class =} \StringTok{"boxxy"}\NormalTok{,}
    \KeywordTok{h1}\NormalTok{(}\DataTypeTok{id =} \KeywordTok{sprintf}\NormalTok{(}\StringTok{"%s-boxxy-value"}\NormalTok{, id), }\DataTypeTok{class =} \StringTok{"boxxy-value"}\NormalTok{),}
    \KeywordTok{p}\NormalTok{(}\DataTypeTok{id =} \KeywordTok{sprintf}\NormalTok{(}\StringTok{"%s-boxxy-title"}\NormalTok{, id), }\DataTypeTok{class =} \StringTok{"boxxy-title"}\NormalTok{)}
\NormalTok{  )}

\NormalTok{  path <-}\StringTok{ }\KeywordTok{normalizePath}\NormalTok{(}\StringTok{"assets"}\NormalTok{)}

\NormalTok{  deps <-}\StringTok{ }\KeywordTok{list}\NormalTok{(}
\NormalTok{    htmltools}\OperatorTok{::}\KeywordTok{htmlDependency}\NormalTok{(}
      \DataTypeTok{name =} \StringTok{"boxxy"}\NormalTok{,}
      \DataTypeTok{version =} \StringTok{"1.0.0"}\NormalTok{,}
      \DataTypeTok{src =} \KeywordTok{c}\NormalTok{(}\DataTypeTok{file =}\NormalTok{ path),}
      \DataTypeTok{script =} \KeywordTok{c}\NormalTok{(}\StringTok{"countup.js"}\NormalTok{, }\StringTok{"binding.js"}\NormalTok{),}
      \DataTypeTok{stylesheet =} \StringTok{"styles.css"}
\NormalTok{    )}
\NormalTok{  )}

\NormalTok{  htmltools}\OperatorTok{::}\KeywordTok{attachDependencies}\NormalTok{(el, deps)}
\NormalTok{\}}

\NormalTok{renderBoxxy <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(expr, }\DataTypeTok{env =} \KeywordTok{parent.frame}\NormalTok{(), }
  \DataTypeTok{quoted =} \OtherTok{FALSE}\NormalTok{) \{}
  \CommentTok{# Convert the expression + environment into a function}
\NormalTok{  func <-}\StringTok{ }\NormalTok{shiny}\OperatorTok{::}\KeywordTok{exprToFunction}\NormalTok{(expr, env, quoted)}

  \ControlFlowTok{function}\NormalTok{()\{}
    \KeywordTok{func}\NormalTok{()}
\NormalTok{  \}}
\NormalTok{\}}

\NormalTok{ui <-}\StringTok{ }\KeywordTok{fluidPage}\NormalTok{(}
  \KeywordTok{h2}\NormalTok{(}\StringTok{"Custom outputs"}\NormalTok{),}
  \KeywordTok{fluidRow}\NormalTok{(}
    \KeywordTok{column}\NormalTok{(}
      \DecValTok{3}\NormalTok{, }\KeywordTok{boxxyOutput}\NormalTok{(}\StringTok{"countries"}\NormalTok{)}
\NormalTok{    ),}
    \KeywordTok{column}\NormalTok{(}
      \DecValTok{3}\NormalTok{, }\KeywordTok{boxxyOutput}\NormalTok{(}\StringTok{"employees"}\NormalTok{)}
\NormalTok{    ),}
    \KeywordTok{column}\NormalTok{(}
      \DecValTok{3}\NormalTok{, }\KeywordTok{boxxyOutput}\NormalTok{(}\StringTok{"customers"}\NormalTok{)}
\NormalTok{    ),}
    \KeywordTok{column}\NormalTok{(}
      \DecValTok{3}\NormalTok{, }\KeywordTok{boxxyOutput}\NormalTok{(}\StringTok{"subs"}\NormalTok{)}
\NormalTok{    )}
\NormalTok{  )}
\NormalTok{)}

\NormalTok{server <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(input, output)\{}
\NormalTok{  output}\OperatorTok{$}\NormalTok{countries <-}\StringTok{ }\KeywordTok{renderBoxxy}\NormalTok{(\{}
    \KeywordTok{boxxy}\NormalTok{(}\StringTok{"Countries"}\NormalTok{, }\DecValTok{95}\NormalTok{, }\DataTypeTok{color =} \StringTok{"#ef476f"}\NormalTok{)}
\NormalTok{  \})}

\NormalTok{  output}\OperatorTok{$}\NormalTok{employees <-}\StringTok{ }\KeywordTok{renderBoxxy}\NormalTok{(\{}
    \KeywordTok{boxxy}\NormalTok{(}\StringTok{"Thing"}\NormalTok{, }\DecValTok{650}\NormalTok{, }\DataTypeTok{color =} \StringTok{"#06d6a0"}\NormalTok{)}
\NormalTok{  \})}

\NormalTok{  output}\OperatorTok{$}\NormalTok{customers <-}\StringTok{ }\KeywordTok{renderBoxxy}\NormalTok{(\{}
    \KeywordTok{boxxy}\NormalTok{(}\StringTok{"Customers"}\NormalTok{, }\DecValTok{13592}\NormalTok{, }\DataTypeTok{color =} \StringTok{"#118ab2"}\NormalTok{)}
\NormalTok{  \})}

\NormalTok{  output}\OperatorTok{$}\NormalTok{subs <-}\StringTok{ }\KeywordTok{renderBoxxy}\NormalTok{(\{}
    \KeywordTok{boxxy}\NormalTok{(}\StringTok{"Subscriptions"}\NormalTok{, }\DecValTok{16719}\NormalTok{, }\DataTypeTok{color =} \StringTok{"#ffd166"}\NormalTok{)}
\NormalTok{  \})}
\NormalTok{\}}

\KeywordTok{shinyApp}\NormalTok{(ui, server)}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/custom-output-boxxy} 

}

\caption{Shiny application with boxxy}\label{fig:boxxy-custom}
\end{figure}

\hypertarget{shiny-output-inject}{%
\section{Injecting Dependencies}\label{shiny-output-inject}}

We could consider making the animation of the value rendered with \texttt{boxxy} optional; some users may not want to use it. You might already imagine how a new argument and a few if-statements could very quickly do the job, but how would one handle the dependency\index{dependency}? Indeed if users do not want to make use of the animation, the CountUp.js dependency should also be excluded so as to keep the output as light as possible.

The dependency is currently attached in the \texttt{boxxyOutput} function, which does not take any argument. It could, but it would make for the rather messy and confusing interface as whatever additional argument that indicates whether the numbers should be animated would have to be specified twice. Once in the \texttt{boxxyOutput} function, so it does not import the dependency\index{dependency}, as well as in the \texttt{boxxy} function in order to serialise that parameter, so the JavaScript binding does not run the animation function.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# pseudo code}
\CommentTok{# do not do this}
\KeywordTok{library}\NormalTok{(shiny)}

\NormalTok{ui <-}\StringTok{ }\KeywordTok{fluidPage}\NormalTok{(}
  \KeywordTok{boxxyOutput}\NormalTok{(}
    \StringTok{"countries"}\NormalTok{, }
    \CommentTok{# do not import dependency}
    \DataTypeTok{animate =} \OtherTok{FALSE}
\NormalTok{  )}
\NormalTok{)}

\NormalTok{server <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(input, output)\{}
\NormalTok{  output}\OperatorTok{$}\NormalTok{countries <-}\StringTok{ }\KeywordTok{renderBoxxy}\NormalTok{(\{}
    \CommentTok{# do not animate the numbers}
    \KeywordTok{boxxy}\NormalTok{(}\StringTok{"Countries"}\NormalTok{, }\DecValTok{95}\NormalTok{, }\DataTypeTok{animate =} \OtherTok{FALSE}\NormalTok{)}
\NormalTok{  \})}
\NormalTok{\}}

\KeywordTok{shinyApp}\NormalTok{(ui, server)}
\end{Highlighting}
\end{Shaded}

Thankfully there is a better way, combining htmltools and Shiny to insert the dependency\index{dependency} dynamically from JavaScript.

The \texttt{boxxy} function needs to take an additional argument \texttt{animate}, which is passed to the output list. This will be used in the \texttt{render} function (and JavaScript binding) to render the dependency\index{dependency} dynamically.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{boxxy <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(title, value, }\DataTypeTok{color =} \StringTok{"black"}\NormalTok{, }\DataTypeTok{animate =} \OtherTok{TRUE}\NormalTok{)\{}
  \KeywordTok{list}\NormalTok{(}
    \DataTypeTok{title =}\NormalTok{ title, }\DataTypeTok{value =}\NormalTok{ value, }\DataTypeTok{color =}\NormalTok{ color, }\DataTypeTok{animate =}\NormalTok{ animate}
\NormalTok{  )}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

The \texttt{boxxyOutput} function can be slightly simplified. It currently attaches the \texttt{countup.js} dependency\index{dependency}, which needs to be removed.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{boxxyOutput <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(id)\{}
\NormalTok{  el <-}\StringTok{ }\NormalTok{shiny}\OperatorTok{::}\NormalTok{tags}\OperatorTok{$}\KeywordTok{div}\NormalTok{(}
    \DataTypeTok{id =}\NormalTok{ id, }\DataTypeTok{class =} \StringTok{"boxxy"}\NormalTok{,}
    \KeywordTok{h1}\NormalTok{(}\DataTypeTok{id =} \KeywordTok{sprintf}\NormalTok{(}\StringTok{"%s-boxxy-value"}\NormalTok{, id), }\DataTypeTok{class =} \StringTok{"boxxy-value"}\NormalTok{),}
    \KeywordTok{p}\NormalTok{(}\DataTypeTok{id =} \KeywordTok{sprintf}\NormalTok{(}\StringTok{"%s-boxxy-title"}\NormalTok{, id), }\DataTypeTok{class =} \StringTok{"boxxy-title"}\NormalTok{)}
\NormalTok{  )}

\NormalTok{  path <-}\StringTok{ }\KeywordTok{normalizePath}\NormalTok{(}\StringTok{"assets"}\NormalTok{)}

  \CommentTok{# only attach binding.js}
\NormalTok{  deps <-}\StringTok{ }\KeywordTok{list}\NormalTok{(}
\NormalTok{    htmltools}\OperatorTok{::}\KeywordTok{htmlDependency}\NormalTok{(}
      \DataTypeTok{name =} \StringTok{"boxxy"}\NormalTok{,}
      \DataTypeTok{version =} \StringTok{"1.0.0"}\NormalTok{,}
      \DataTypeTok{src =} \KeywordTok{c}\NormalTok{(}\DataTypeTok{file =}\NormalTok{ path),}
      \DataTypeTok{script =} \KeywordTok{c}\NormalTok{(}\StringTok{"binding.js"}\NormalTok{),}
      \DataTypeTok{stylesheet =} \StringTok{"styles.css"}
\NormalTok{    )}
\NormalTok{  )}

\NormalTok{  htmltools}\OperatorTok{::}\KeywordTok{attachDependencies}\NormalTok{(el, deps)}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

The \texttt{renderBoxxy} function sees some modifications, while before it was technically only returning a function that itself returned the output of \texttt{boxxy} (\texttt{func()\ ==\ boxxy()}). Here we want to capture the output of \texttt{boxxy} to check whether the \texttt{animate} element is \texttt{TRUE} and, if so, add the dependency\index{dependency}.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{renderBoxxy <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(expr, }\DataTypeTok{env =} \KeywordTok{parent.frame}\NormalTok{(), }
  \DataTypeTok{quoted =} \OtherTok{FALSE}\NormalTok{) \{}
  \CommentTok{# Convert the expression + environment into a function}
\NormalTok{  func <-}\StringTok{ }\NormalTok{shiny}\OperatorTok{::}\KeywordTok{exprToFunction}\NormalTok{(expr, env, quoted)}

  \ControlFlowTok{function}\NormalTok{()\{}
\NormalTok{    val <-}\StringTok{ }\KeywordTok{func}\NormalTok{()}

    \ControlFlowTok{if}\NormalTok{(val}\OperatorTok{$}\NormalTok{animate)\{}
      \CommentTok{# add dependency}
\NormalTok{    \}}

    \KeywordTok{return}\NormalTok{(val)}
\NormalTok{  \}}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

Within the \texttt{if} statement, the dependency can be created with the htmltools as done for the binding. Ensure the names of the dependencies\index{dependency} are unique as shiny internally uses it to differentiate between them; if they bear the same name Shiny assumes they are the same and will only render one of them.

\begin{rmdnote}
Make sure dependencies\index{dependency} bear different names or Shiny
thinks it's the same and only renders one of them.
\end{rmdnote}

The dependency generated with htmltools is then passed to the \texttt{shiny::createWebDependency} function, which internally uses \texttt{shiny::addResourcePath} to serve the dependency. This is necessary here as, at this stage, the countup dependency\index{dependency} is not actually rendered; below we merely add it to the list of options that serialised to JSON\index{JSON}. Indeed, this will actually be injected JavaScript-side. Therefore the front end needs to be able to access this file, hence it is served.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{renderBoxxy <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(expr, }\DataTypeTok{env =} \KeywordTok{parent.frame}\NormalTok{(), }
  \DataTypeTok{quoted =} \OtherTok{FALSE}\NormalTok{) \{}
  \CommentTok{# Convert the expression + environment into a function}
\NormalTok{  func <-}\StringTok{ }\NormalTok{shiny}\OperatorTok{::}\KeywordTok{exprToFunction}\NormalTok{(expr, env, quoted)}

  \ControlFlowTok{function}\NormalTok{()\{}
    \CommentTok{# evaluate to output list}
\NormalTok{    val <-}\StringTok{ }\KeywordTok{func}\NormalTok{()}

    \CommentTok{# add dependency}
    \ControlFlowTok{if}\NormalTok{(val}\OperatorTok{$}\NormalTok{animate)\{}
\NormalTok{      path <-}\StringTok{ }\KeywordTok{normalizePath}\NormalTok{(}\StringTok{"assets"}\NormalTok{)}

\NormalTok{      deps <-}\StringTok{ }\NormalTok{htmltools}\OperatorTok{::}\KeywordTok{htmlDependency}\NormalTok{(}
        \DataTypeTok{name =} \StringTok{"countup"}\NormalTok{, }\CommentTok{# change name}
        \DataTypeTok{version =} \StringTok{"1.8.2"}\NormalTok{,}
        \DataTypeTok{src =} \KeywordTok{c}\NormalTok{(}\DataTypeTok{file =}\NormalTok{ path),}
        \DataTypeTok{script =} \KeywordTok{c}\NormalTok{(}\StringTok{"countup.js"}\NormalTok{) }\CommentTok{# only countup}
\NormalTok{      )}

      \CommentTok{# serve dependency }
\NormalTok{      val}\OperatorTok{$}\NormalTok{deps <-}\StringTok{ }\KeywordTok{list}\NormalTok{(shiny}\OperatorTok{::}\KeywordTok{createWebDependency}\NormalTok{(deps))}
\NormalTok{    \}}

    \KeywordTok{return}\NormalTok{(val)}
\NormalTok{  \}}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

Thus far, the dependency\index{dependency} is dynamically included in the R object; that is serialised to JSON, but it is not yet actually imported in the document---this happens in the JavaScript binding.

The first thing we ought to do is mirror the if-statement that was created in the \texttt{renderBoxxy} function. If the numbers should be animated, the function can use countup; if not, it must insert the text with \texttt{insertText} just like it does for the \texttt{title}.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{var}\NormalTok{ boxxyBinding }\OperatorTok{=} \KeywordTok{new} \VariableTok{Shiny}\NormalTok{.}\AttributeTok{OutputBinding}\NormalTok{()}\OperatorTok{;}

\VariableTok{$}\NormalTok{.}\AttributeTok{extend}\NormalTok{(boxxyBinding}\OperatorTok{,} \OperatorTok{\{}
  \DataTypeTok{find}\OperatorTok{:} \KeywordTok{function}\NormalTok{(scope) }\OperatorTok{\{}
    \ControlFlowTok{return} \AttributeTok{$}\NormalTok{(scope).}\AttributeTok{find}\NormalTok{(}\StringTok{".boxxy"}\NormalTok{)}\OperatorTok{;}
  \OperatorTok{\},}
  \DataTypeTok{renderValue}\OperatorTok{:} \KeywordTok{function}\NormalTok{(el}\OperatorTok{,}\NormalTok{ data) }\OperatorTok{\{}

    \KeywordTok{let}\NormalTok{ boxValue}\OperatorTok{,}\NormalTok{ boxTitle}\OperatorTok{;}

    \VariableTok{el}\NormalTok{.}\VariableTok{style}\NormalTok{.}\AttributeTok{backgroundColor} \OperatorTok{=} \VariableTok{data}\NormalTok{.}\AttributeTok{color}\OperatorTok{;}

    \ControlFlowTok{if}\NormalTok{(}\VariableTok{data}\NormalTok{.}\AttributeTok{animate}\NormalTok{)}\OperatorTok{\{}
      \KeywordTok{var}\NormalTok{ counter }\OperatorTok{=} \KeywordTok{new} \AttributeTok{CountUp}\NormalTok{(}
        \VariableTok{el}\NormalTok{.}\AttributeTok{id} \OperatorTok{+} \StringTok{'-boxxy-value'}\OperatorTok{,} \DecValTok{0}\OperatorTok{,} \VariableTok{data}\NormalTok{.}\AttributeTok{value}
\NormalTok{      )}\OperatorTok{;}
      \VariableTok{counter}\NormalTok{.}\AttributeTok{start}\NormalTok{()}\OperatorTok{;}
    \OperatorTok{\}} \ControlFlowTok{else} \OperatorTok{\{}
\NormalTok{      boxValue }\OperatorTok{=} \VariableTok{document}\NormalTok{.}\AttributeTok{getElementById}\NormalTok{(}\VariableTok{el}\NormalTok{.}\AttributeTok{id} \OperatorTok{+} \StringTok{'-boxxy-value'}\NormalTok{)}
      \VariableTok{boxValue}\NormalTok{.}\AttributeTok{innerText} \OperatorTok{=} \VariableTok{data}\NormalTok{.}\AttributeTok{value}\OperatorTok{;}
    \OperatorTok{\}}

\NormalTok{    boxTitle }\OperatorTok{=} \VariableTok{document}\NormalTok{.}\AttributeTok{getElementById}\NormalTok{(}\VariableTok{el}\NormalTok{.}\AttributeTok{id} \OperatorTok{+} \StringTok{'-boxxy-title'}\NormalTok{)}
    \VariableTok{boxTitle}\NormalTok{.}\AttributeTok{innerText} \OperatorTok{=} \VariableTok{data}\NormalTok{.}\AttributeTok{title}\OperatorTok{;}
  \OperatorTok{\}}
\OperatorTok{\}}\NormalTok{)}\OperatorTok{;}

\VariableTok{Shiny}\NormalTok{.}\VariableTok{outputBindings}\NormalTok{.}\AttributeTok{register}\NormalTok{(boxxyBinding}\OperatorTok{,} \StringTok{"john.boxxy"}\NormalTok{)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

Finally, we can render the dependency. The JavaScript method aptly named \texttt{renderDependencies} will do just that from the list of dependency\index{dependency} created in \texttt{renderBoxxy}.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{var}\NormalTok{ boxxyBinding }\OperatorTok{=} \KeywordTok{new} \VariableTok{Shiny}\NormalTok{.}\AttributeTok{OutputBinding}\NormalTok{()}\OperatorTok{;}

\VariableTok{$}\NormalTok{.}\AttributeTok{extend}\NormalTok{(boxxyBinding}\OperatorTok{,} \OperatorTok{\{}
  \DataTypeTok{find}\OperatorTok{:} \KeywordTok{function}\NormalTok{(scope) }\OperatorTok{\{}
    \ControlFlowTok{return} \AttributeTok{$}\NormalTok{(scope).}\AttributeTok{find}\NormalTok{(}\StringTok{".boxxy"}\NormalTok{)}\OperatorTok{;}
  \OperatorTok{\},}
  \DataTypeTok{renderValue}\OperatorTok{:} \KeywordTok{function}\NormalTok{(el}\OperatorTok{,}\NormalTok{ data) }\OperatorTok{\{}

    \KeywordTok{let}\NormalTok{ boxValue}\OperatorTok{,}\NormalTok{ boxTitle}\OperatorTok{;}

    \VariableTok{el}\NormalTok{.}\VariableTok{style}\NormalTok{.}\AttributeTok{backgroundColor} \OperatorTok{=} \VariableTok{data}\NormalTok{.}\AttributeTok{color}\OperatorTok{;}

    \ControlFlowTok{if}\NormalTok{(}\VariableTok{data}\NormalTok{.}\AttributeTok{animate}\NormalTok{)}\OperatorTok{\{}
      \VariableTok{Shiny}\NormalTok{.}\AttributeTok{renderDependencies}\NormalTok{(}\VariableTok{data}\NormalTok{.}\AttributeTok{deps}\NormalTok{)}\OperatorTok{;} \CommentTok{// render dependency}
      \KeywordTok{var}\NormalTok{ counter }\OperatorTok{=} \KeywordTok{new} \AttributeTok{CountUp}\NormalTok{(}
        \VariableTok{el}\NormalTok{.}\AttributeTok{id} \OperatorTok{+} \StringTok{'-boxxy-value'}\OperatorTok{,} \DecValTok{0}\OperatorTok{,} \VariableTok{data}\NormalTok{.}\AttributeTok{value}
\NormalTok{      )}\OperatorTok{;}
      \VariableTok{counter}\NormalTok{.}\AttributeTok{start}\NormalTok{()}\OperatorTok{;}
    \OperatorTok{\}} \ControlFlowTok{else} \OperatorTok{\{}
\NormalTok{      boxValue }\OperatorTok{=} \VariableTok{document}\NormalTok{.}\AttributeTok{getElementById}\NormalTok{(}\VariableTok{el}\NormalTok{.}\AttributeTok{id} \OperatorTok{+} \StringTok{'-boxxy-value'}\NormalTok{)}
      \VariableTok{boxValue}\NormalTok{.}\AttributeTok{innerText} \OperatorTok{=} \VariableTok{data}\NormalTok{.}\AttributeTok{value}\OperatorTok{;}
    \OperatorTok{\}}

\NormalTok{    boxTitle }\OperatorTok{=} \VariableTok{document}\NormalTok{.}\AttributeTok{getElementById}\NormalTok{(}\VariableTok{el}\NormalTok{.}\AttributeTok{id} \OperatorTok{+} \StringTok{'-boxxy-title'}\NormalTok{)}
    \VariableTok{boxTitle}\NormalTok{.}\AttributeTok{innerText} \OperatorTok{=} \VariableTok{data}\NormalTok{.}\AttributeTok{title}\OperatorTok{;}
  \OperatorTok{\}}
\OperatorTok{\}}\NormalTok{)}\OperatorTok{;}

\VariableTok{Shiny}\NormalTok{.}\VariableTok{outputBindings}\NormalTok{.}\AttributeTok{register}\NormalTok{(boxxyBinding}\OperatorTok{,} \StringTok{"john.boxxy"}\NormalTok{)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

With those changes made, not only is the animation of numbers optional, but if users decide to turn off the animation in all \texttt{boxxy} functions, the \texttt{countup.js} file will not be included at all.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(shiny)}

\NormalTok{ui <-}\StringTok{ }\KeywordTok{fluidPage}\NormalTok{(}
  \KeywordTok{h2}\NormalTok{(}\StringTok{"Custom outputs"}\NormalTok{),}
  \KeywordTok{fluidRow}\NormalTok{(}
    \KeywordTok{column}\NormalTok{(}
      \DecValTok{3}\NormalTok{, }\KeywordTok{boxxyOutput}\NormalTok{(}\StringTok{"countries"}\NormalTok{)}
\NormalTok{    ),}
    \KeywordTok{column}\NormalTok{(}
      \DecValTok{3}\NormalTok{, }\KeywordTok{boxxyOutput}\NormalTok{(}\StringTok{"employees"}\NormalTok{)}
\NormalTok{    )}
\NormalTok{  )}
\NormalTok{)}

\NormalTok{server <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(input, output)\{}
\NormalTok{  output}\OperatorTok{$}\NormalTok{countries <-}\StringTok{ }\KeywordTok{renderBoxxy}\NormalTok{(\{}
    \KeywordTok{boxxy}\NormalTok{(}\StringTok{"Countries"}\NormalTok{, }\DecValTok{176}\NormalTok{, }\DataTypeTok{animate =} \OtherTok{FALSE}\NormalTok{)}
\NormalTok{  \})}

\NormalTok{  output}\OperatorTok{$}\NormalTok{employees <-}\StringTok{ }\KeywordTok{renderBoxxy}\NormalTok{(\{}
    \KeywordTok{boxxy}\NormalTok{(}\StringTok{"Thing"}\NormalTok{, }\DecValTok{67}\NormalTok{, }\DataTypeTok{animate =} \OtherTok{FALSE}\NormalTok{)}
\NormalTok{  \})}
\NormalTok{\}}

\KeywordTok{shinyApp}\NormalTok{(ui, server)}
\end{Highlighting}
\end{Shaded}

\hypertarget{shiny-output-preprocess}{%
\section{Preprocessing Custom Outputs}\label{shiny-output-preprocess}}

One aspect that this example did not truly explore thus far is the idea that the function \texttt{boxxy} should preprocess the input more in order to be truly justified. Currently \texttt{boxxy} only wraps the arguments in a \texttt{list}. Therefore, the code below works too.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# works too}
\NormalTok{output}\OperatorTok{$}\NormalTok{theId <-}\StringTok{ }\KeywordTok{renderBoxxy}\NormalTok{(\{}
  \KeywordTok{list}\NormalTok{(}
    \DataTypeTok{title =} \StringTok{"The Title"}\NormalTok{, }
    \DataTypeTok{value =} \DecValTok{123}\NormalTok{, }
    \DataTypeTok{color =} \StringTok{"blue"}\NormalTok{, }
    \DataTypeTok{animate =} \OtherTok{TRUE}
\NormalTok{  )}
\NormalTok{\})}
\end{Highlighting}
\end{Shaded}

One the things \texttt{boxxy} could do is preprocess the input for instance. Instead of accepting a vector of length one for the \texttt{value} argument, it takes the sum of it to allow vectors of any length and dynamically changes the \texttt{color} depending on \texttt{value}.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{boxxy <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(title, value, }\DataTypeTok{color =} \OtherTok{NULL}\NormalTok{, }\DataTypeTok{animate =} \OtherTok{TRUE}\NormalTok{)\{}

  \CommentTok{# sum the vector}
\NormalTok{  value <-}\StringTok{ }\KeywordTok{sum}\NormalTok{(value)}

  \CommentTok{# dynamic color}
  \ControlFlowTok{if}\NormalTok{(}\KeywordTok{is.null}\NormalTok{(color))}
    \ControlFlowTok{if}\NormalTok{(value }\OperatorTok{>}\StringTok{ }\DecValTok{100}\NormalTok{)}
\NormalTok{      color <-}\StringTok{ "#ef476f"}
    \ControlFlowTok{else}
\NormalTok{      color <-}\StringTok{ "#06d6a0"}

  \KeywordTok{list}\NormalTok{(}
    \DataTypeTok{title =}\NormalTok{ title, }
    \DataTypeTok{value =}\NormalTok{ value, }
    \DataTypeTok{color =}\NormalTok{ color, }
    \DataTypeTok{animate =}\NormalTok{ animate}
\NormalTok{  )}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

This means boxxy could be used like so: \texttt{boxxy("Total",\ c(1,6,9))}.

\hypertarget{shiny-input}{%
\chapter{Custom Inputs}\label{shiny-input}}

Shiny comes with a variety of inputs ranging from buttons to text fields; these inputs send data from the client to the R server. Custom inputs are in fact, no different than from Shiny's out-of-the-box inputs, they work in the same way and are built on the same system.

To explain and demonstrate how to build such a custom input, we shall build a switch input, which is essentially a fancy-looking checkbox that can be toggled on and off.

Custom Shiny\index{Shiny} inputs very much resemble Shiny\index{Shiny} outputs though they consist of a single R function (e.g.: \texttt{selectInput}), which generates the HTML and attaches necessary dependencies\index{dependency}. When run from the R console, such functions will reveal the HTML they generate.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{shiny}\OperatorTok{::}\KeywordTok{textInput}\NormalTok{(}\StringTok{"theId"}\NormalTok{, }\StringTok{"The label"}\NormalTok{)   }
\end{Highlighting}
\end{Shaded}

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{<div}\OtherTok{ class=}\StringTok{"form-group shiny-input-container"}\KeywordTok{>}
  \KeywordTok{<label}\OtherTok{ class=}\StringTok{"control-label"}\OtherTok{ for=}\StringTok{"theId"}\KeywordTok{>}\NormalTok{The label}\KeywordTok{</label>}
  \KeywordTok{<input}\OtherTok{ id=}\StringTok{"theId"}\OtherTok{ type=}\StringTok{"text"}\OtherTok{ class=}\StringTok{"form-control"}\OtherTok{ value=}\StringTok{""}\KeywordTok{/>}
\KeywordTok{</div>}
\end{Highlighting}
\end{Shaded}

The R function is paired with a JavaScript input binding akin to the output binding used in the previous chapter.

\hypertarget{shiny-input-setup}{%
\section{Setup}\label{shiny-input-setup}}

Let us set up the necessary files and project structure. Below an asset\index{asset} directory is created. In it, we place a JavaScript file where the binding will be coded, as well as a CSS file that will style the switch input, an \texttt{app.R} file is also created to hold the R code and application.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# create directory for application}
\KeywordTok{dir.create}\NormalTok{(}\StringTok{"switch/assets"}\NormalTok{, }\DataTypeTok{recursive =} \OtherTok{TRUE}\NormalTok{)}

\CommentTok{# create R, JS, and CSS files}
\KeywordTok{file.create}\NormalTok{(}\StringTok{"app.R"}\NormalTok{)}
\KeywordTok{file.create}\NormalTok{(}\StringTok{"switch/assets/binding.js"}\NormalTok{)}
\KeywordTok{file.create}\NormalTok{(}\StringTok{"switch/assets/styles.css"}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

This should create the following directory structure.

\begin{verbatim}
.
├── app.R
└── assets
    ├── binding.js
    └── styles.css
\end{verbatim}

\hypertarget{shiny-input-intro}{%
\section{Switch Input HTML and Style}\label{shiny-input-intro}}

We will use \href{https://www.w3schools.com/howto/howto_css_switch.asp}{w3schools}' switch input template.

The HTML of the input looks like so.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{<label}\OtherTok{ class=}\StringTok{"switch"}\KeywordTok{>}
  \KeywordTok{<input}\OtherTok{ type=}\StringTok{"checkbox"}\KeywordTok{>}
  \KeywordTok{<span}\OtherTok{ class=}\StringTok{"slider"}\KeywordTok{></span>}
\KeywordTok{</label>}
\end{Highlighting}
\end{Shaded}

While the CSS which stylises the checkbox input into a switch is the following.

\begin{Shaded}
\begin{Highlighting}[]
\FunctionTok{.switch}\NormalTok{ \{}
  \KeywordTok{position}\NormalTok{: }\DecValTok{relative}\OperatorTok{;}
  \KeywordTok{display}\NormalTok{: }\DecValTok{inline-block}\OperatorTok{;}
  \KeywordTok{width}\NormalTok{: }\DecValTok{60}\DataTypeTok{px}\OperatorTok{;}
  \KeywordTok{height}\NormalTok{: }\DecValTok{34}\DataTypeTok{px}\OperatorTok{;}
\NormalTok{\}}

\FunctionTok{.switch}\NormalTok{ input \{ }
  \KeywordTok{opacity}\NormalTok{: }\DecValTok{0}\OperatorTok{;}
  \KeywordTok{width}\NormalTok{: }\DecValTok{0}\OperatorTok{;}
  \KeywordTok{height}\NormalTok{: }\DecValTok{0}\OperatorTok{;}
\NormalTok{\}}

\FunctionTok{.slider}\NormalTok{ \{}
  \KeywordTok{position}\NormalTok{: }\DecValTok{absolute}\OperatorTok{;}
  \KeywordTok{cursor}\NormalTok{: }\DecValTok{pointer}\OperatorTok{;}
  \KeywordTok{top}\NormalTok{: }\DecValTok{0}\OperatorTok{;}
  \KeywordTok{left}\NormalTok{: }\DecValTok{0}\OperatorTok{;}
  \KeywordTok{right}\NormalTok{: }\DecValTok{0}\OperatorTok{;}
  \KeywordTok{bottom}\NormalTok{: }\DecValTok{0}\OperatorTok{;}
  \KeywordTok{background-color}\NormalTok{: }\ConstantTok{#ccc}\OperatorTok{;}
  \KeywordTok{-webkit-transition}\NormalTok{: }\DecValTok{.4}\DataTypeTok{s}\OperatorTok{;}
  \KeywordTok{transition}\NormalTok{: }\DecValTok{.4}\DataTypeTok{s}\OperatorTok{;}
\NormalTok{\}}

\FunctionTok{.slider}\InformationTok{:before}\NormalTok{ \{}
  \KeywordTok{position}\NormalTok{: }\DecValTok{absolute}\OperatorTok{;}
  \KeywordTok{content}\NormalTok{: }\StringTok{""}\OperatorTok{;}
  \KeywordTok{height}\NormalTok{: }\DecValTok{26}\DataTypeTok{px}\OperatorTok{;}
  \KeywordTok{width}\NormalTok{: }\DecValTok{26}\DataTypeTok{px}\OperatorTok{;}
  \KeywordTok{left}\NormalTok{: }\DecValTok{4}\DataTypeTok{px}\OperatorTok{;}
  \KeywordTok{bottom}\NormalTok{: }\DecValTok{4}\DataTypeTok{px}\OperatorTok{;}
  \KeywordTok{background-color}\NormalTok{: }\ConstantTok{white}\OperatorTok{;}
  \KeywordTok{-webkit-transition}\NormalTok{: }\DecValTok{.4}\DataTypeTok{s}\OperatorTok{;}
  \KeywordTok{transition}\NormalTok{: }\DecValTok{.4}\DataTypeTok{s}\OperatorTok{;}
\NormalTok{\}}

\NormalTok{input}\InformationTok{:checked} \OperatorTok{+} \FunctionTok{.slider}\NormalTok{ \{}
  \KeywordTok{background-color}\NormalTok{: }\ConstantTok{#0462a1}\OperatorTok{;}
\NormalTok{\}}

\NormalTok{input}\InformationTok{:focus} \OperatorTok{+} \FunctionTok{.slider}\NormalTok{ \{}
  \KeywordTok{box-shadow}\NormalTok{: }\DecValTok{0} \DecValTok{0} \DecValTok{1}\DataTypeTok{px} \ConstantTok{#0462a1}\OperatorTok{;}
\NormalTok{\}}

\NormalTok{input}\InformationTok{:checked} \OperatorTok{+} \FunctionTok{.slider}\InformationTok{:before}\NormalTok{ \{}
  \KeywordTok{-webkit-transform}\NormalTok{: translateX(}\DecValTok{26}\DataTypeTok{px}\NormalTok{)}\OperatorTok{;}
  \KeywordTok{-ms-transform}\NormalTok{: translateX(}\DecValTok{26}\DataTypeTok{px}\NormalTok{)}\OperatorTok{;}
  \KeywordTok{transform}\NormalTok{: translateX(}\DecValTok{26}\DataTypeTok{px}\NormalTok{)}\OperatorTok{;}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

The above CSS should be placed in the previously created \texttt{assets/styles.css} file. Figure \ref{fig:checkbox-switch} displays an unstyled checkbox and another styled with the above CSS.

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/checkbox-switch} 

}

\caption{Checkbox and styled switch input}\label{fig:checkbox-switch}
\end{figure}

\hypertarget{shiny-input-html}{%
\section{Generate Input HTML}\label{shiny-input-html}}

Let us start with the R function to be used in the Shiny UI. The \texttt{\textless{}input\textgreater{}} it generates bears a \texttt{switchInput} class, which will be used to identify all switch inputs from JavaScript. This was also done in the custom output. The function accepts an \texttt{id} argument; this is also common across all inputs and outputs as a unique identifier is required in order to retrieve the input JavaScript-side.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# app.R}
\NormalTok{switchInput <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(id) \{}

\NormalTok{  tags}\OperatorTok{$}\KeywordTok{input}\NormalTok{(}
    \DataTypeTok{id =}\NormalTok{ id, }
    \DataTypeTok{type =} \StringTok{"checkbox"}\NormalTok{, }
    \DataTypeTok{class =} \StringTok{"switchInput"}
\NormalTok{  )}

\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

The function should also accept a customary label and a \texttt{checked} argument to define the initial state of the switch.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# app.R}
\NormalTok{switchInput <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(id, label, }\DataTypeTok{checked =} \OtherTok{TRUE}\NormalTok{) \{}

\NormalTok{  input <-}\StringTok{ }\NormalTok{tags}\OperatorTok{$}\KeywordTok{input}\NormalTok{(}
    \DataTypeTok{id =}\NormalTok{ id, }
    \DataTypeTok{type =} \StringTok{"checkbox"}\NormalTok{, }
    \DataTypeTok{class =} \StringTok{"switchInput"}
\NormalTok{  )}

  \ControlFlowTok{if}\NormalTok{(checked)}
\NormalTok{    input <-}\StringTok{ }\NormalTok{htmltools}\OperatorTok{::}\KeywordTok{tagAppendAttributes}\NormalTok{(input, }\DataTypeTok{checked =} \OtherTok{NA}\NormalTok{)}

\NormalTok{  form <-}\StringTok{ }\KeywordTok{tagList}\NormalTok{(}
    \KeywordTok{p}\NormalTok{(label),}
\NormalTok{    tags}\OperatorTok{$}\KeywordTok{label}\NormalTok{(}
      \DataTypeTok{class =} \StringTok{"switch"}\NormalTok{,}
\NormalTok{      input,}
\NormalTok{      tags}\OperatorTok{$}\KeywordTok{span}\NormalTok{(}\DataTypeTok{class =} \StringTok{"slider"}\NormalTok{)}
\NormalTok{    )}
\NormalTok{  )}

  \KeywordTok{return}\NormalTok{(form)}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

As for the custom outputs, the dependencies\index{dependency} (CSS and JavaScript binding) can piggy back on the generated HTML.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# app.R}
\NormalTok{switchInput <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(id, label, }\DataTypeTok{checked =} \OtherTok{TRUE}\NormalTok{) \{}

\NormalTok{  input <-}\StringTok{ }\NormalTok{tags}\OperatorTok{$}\KeywordTok{input}\NormalTok{(}
    \DataTypeTok{id =}\NormalTok{ id, }
    \DataTypeTok{type =} \StringTok{"checkbox"}\NormalTok{, }
    \DataTypeTok{class =} \StringTok{"switchInput"}
\NormalTok{  )}

  \ControlFlowTok{if}\NormalTok{(checked)}
\NormalTok{    input <-}\StringTok{ }\NormalTok{htmltools}\OperatorTok{::}\KeywordTok{tagAppendAttributes}\NormalTok{(input, }\DataTypeTok{checked =} \OtherTok{NA}\NormalTok{)}

\NormalTok{  form <-}\StringTok{ }\KeywordTok{tagList}\NormalTok{(}
    \KeywordTok{p}\NormalTok{(label),}
\NormalTok{    tags}\OperatorTok{$}\KeywordTok{label}\NormalTok{(}
      \DataTypeTok{class =} \StringTok{"switch"}\NormalTok{,}
\NormalTok{      input,}
\NormalTok{      tags}\OperatorTok{$}\KeywordTok{span}\NormalTok{(}\DataTypeTok{class =} \StringTok{"slider"}\NormalTok{)}
\NormalTok{    )}
\NormalTok{  )}

\NormalTok{  path <-}\StringTok{ }\KeywordTok{normalizePath}\NormalTok{(}\StringTok{"./assets"}\NormalTok{)}

\NormalTok{  deps <-}\StringTok{ }\NormalTok{htmltools}\OperatorTok{::}\KeywordTok{htmlDependency}\NormalTok{(}
    \DataTypeTok{name =} \StringTok{"switchInput"}\NormalTok{,}
    \DataTypeTok{version =} \StringTok{"1.0.0"}\NormalTok{,}
    \DataTypeTok{src =} \KeywordTok{c}\NormalTok{(}\DataTypeTok{file =}\NormalTok{ path),}
    \DataTypeTok{script =} \StringTok{"binding.js"}\NormalTok{,}
    \DataTypeTok{stylesheet =} \StringTok{"styles.css"}
\NormalTok{  )}

\NormalTok{  htmltools}\OperatorTok{::}\KeywordTok{attachDependencies}\NormalTok{(form, deps)}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

\hypertarget{shiny-input-binding}{%
\section{JavaScript Input Binding}\label{shiny-input-binding}}

The JavaScript input binding is instantiated from \texttt{Shiny.InputBinding}, this is similar to output bindings which are instantiated from \texttt{Shiny.OutputBinding}.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{var}\NormalTok{ switchInput }\OperatorTok{=} \KeywordTok{new} \VariableTok{Shiny}\NormalTok{.}\AttributeTok{InputBinding}\NormalTok{()}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

Then again the binding is ``extended.'' This consists of adding several methods.

\begin{itemize}
\tightlist
\item
  \texttt{find} returns all the relevant inputs.
\item
  \texttt{getId} returns the unique identifier of the input.
\item
  \texttt{getValue} returns the value of the input to be sent to the server.
\item
  \texttt{setValue} is used to set the value of the input.
\item
  \texttt{receiveMessage} is used to receive messages from the server.
\item
  \texttt{subscribe} tells Shiny when and how to send the updated input value to the server.
\item
  \texttt{unsubscribe} removes event handlers and stops Shiny from sending updated values to the server.
\end{itemize}

\hypertarget{shiny-input-find}{%
\subsection{Find Inputs}\label{shiny-input-find}}

The \texttt{find} method looks for all the relevant HTML elements in the document (\texttt{scope}) and returns them as an array. Many other methods we are about to implement will accept \texttt{el} as an argument; this will ultimately be one of the elements returned by \texttt{find}.

Generally, the \texttt{find} method is used in conjunction with a \texttt{class}; hence the \texttt{\textless{}input\textgreater{}} generated by \texttt{switchInput} bears a class of the same name \texttt{switchInput}.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{var}\NormalTok{ switchInput }\OperatorTok{=} \KeywordTok{new} \VariableTok{Shiny}\NormalTok{.}\AttributeTok{InputBinding}\NormalTok{()}\OperatorTok{;}

\VariableTok{$}\NormalTok{.}\AttributeTok{extend}\NormalTok{(switchInput}\OperatorTok{,} \OperatorTok{\{}
  \CommentTok{// find inputs}
  \DataTypeTok{find}\OperatorTok{:} \KeywordTok{function}\NormalTok{(scope) }\OperatorTok{\{}
    \ControlFlowTok{return} \AttributeTok{$}\NormalTok{(scope).}\AttributeTok{find}\NormalTok{(}\StringTok{".switchInput"}\NormalTok{)}\OperatorTok{;}
  \OperatorTok{\}}
\OperatorTok{\}}\NormalTok{)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

\hypertarget{shiny-input-get-id}{%
\subsection{Get Input Id}\label{shiny-input-get-id}}

The \texttt{getId} method is exactly what it appears to be; it returns the \texttt{id} of the element. It looks for that id as \texttt{data-input-id} attribute, and if that is not found returns the \texttt{id}; this can be observed in the \href{https://github.com/rstudio/shiny/blob/master/srcjs/input_binding.js\#L9}{source code} (below).

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{this}\NormalTok{.}\AttributeTok{getId} \OperatorTok{=} \KeywordTok{function}\NormalTok{(el) }\OperatorTok{\{}
  \ControlFlowTok{return}\NormalTok{ el[}\StringTok{'data-input-id'}\NormalTok{] }\OperatorTok{||} \VariableTok{el}\NormalTok{.}\AttributeTok{id}\OperatorTok{;}
\OperatorTok{\};}
\end{Highlighting}
\end{Shaded}

Since the default works, there is no need to use it for the switch input.

\hypertarget{shiny-input-get-value}{%
\subsection{Get Input Value}\label{shiny-input-get-value}}

That retrieves the value of the input; this is often the attribute of the same name (\texttt{value="something"}), which can be obtained with the jQuery\index{jQuery} \texttt{val()} method. The switch is an input of type \texttt{checkbox} and therefore uses the \texttt{checked} prop.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{var}\NormalTok{ switchInput }\OperatorTok{=} \KeywordTok{new} \VariableTok{Shiny}\NormalTok{.}\AttributeTok{InputBinding}\NormalTok{()}\OperatorTok{;}

\VariableTok{$}\NormalTok{.}\AttributeTok{extend}\NormalTok{(switchInput}\OperatorTok{,} \OperatorTok{\{}
  \DataTypeTok{find}\OperatorTok{:} \KeywordTok{function}\NormalTok{(scope) }\OperatorTok{\{}
    \ControlFlowTok{return} \AttributeTok{$}\NormalTok{(scope).}\AttributeTok{find}\NormalTok{(}\StringTok{".switchInput"}\NormalTok{)}\OperatorTok{;}
  \OperatorTok{\},}
  \CommentTok{// retrieve value}
  \DataTypeTok{getValue}\OperatorTok{:} \KeywordTok{function}\NormalTok{(el) }\OperatorTok{\{}
    \ControlFlowTok{return} \AttributeTok{$}\NormalTok{(el).}\AttributeTok{prop}\NormalTok{(}\StringTok{"checked"}\NormalTok{)}\OperatorTok{;}
  \OperatorTok{\}}
\OperatorTok{\}}\NormalTok{)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

The value of the \texttt{checked} prop is boolean, \texttt{true} if checked and \texttt{false} if unchecked.

\begin{rmdnote}
Ensure the \texttt{getValue} method actually \texttt{return}s the value.
\end{rmdnote}

\hypertarget{shiny-input-set-value}{%
\subsection{Set Input Value}\label{shiny-input-set-value}}

The \texttt{setValue} method sets the value of the input; hence it also accepts the \texttt{value} object: the actual value to which the input should be set. Then again, most inputs will likely use the \texttt{value} attribute, which can be set in jQuery\index{jQuery} with \texttt{val(newValue)}, but the checkbox uses the \texttt{checked} prop.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{var}\NormalTok{ switchInput }\OperatorTok{=} \KeywordTok{new} \VariableTok{Shiny}\NormalTok{.}\AttributeTok{InputBinding}\NormalTok{()}\OperatorTok{;}

\VariableTok{$}\NormalTok{.}\AttributeTok{extend}\NormalTok{(switchInput}\OperatorTok{,} \OperatorTok{\{}
  \DataTypeTok{find}\OperatorTok{:} \KeywordTok{function}\NormalTok{(scope) }\OperatorTok{\{}
    \ControlFlowTok{return} \AttributeTok{$}\NormalTok{(scope).}\AttributeTok{find}\NormalTok{(}\StringTok{".switchInput"}\NormalTok{)}\OperatorTok{;}
  \OperatorTok{\},}
  \DataTypeTok{getValue}\OperatorTok{:} \KeywordTok{function}\NormalTok{(el) }\OperatorTok{\{}
    \ControlFlowTok{return} \AttributeTok{$}\NormalTok{(el).}\AttributeTok{prop}\NormalTok{(}\StringTok{"checked"}\NormalTok{)}\OperatorTok{;}
  \OperatorTok{\},}
  \CommentTok{// check or uncheck the switch}
  \DataTypeTok{setValue}\OperatorTok{:} \KeywordTok{function}\NormalTok{(el}\OperatorTok{,}\NormalTok{ value) }\OperatorTok{\{}
    \AttributeTok{$}\NormalTok{(el).}\AttributeTok{prop}\NormalTok{(}\StringTok{"checked"}\OperatorTok{,}\NormalTok{ value).}\AttributeTok{change}\NormalTok{()}\OperatorTok{;}
  \OperatorTok{\}}
\OperatorTok{\}}\NormalTok{)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

Note the use of the \texttt{change} method, which ensures the event is fired. Otherwise the input is checked or unchecked, but the \texttt{change} event is not fired, and this will cause problems later on as we rely on this event.

\hypertarget{shiny-input-receive-msg}{%
\subsection{Receive Input Messages}\label{shiny-input-receive-msg}}

The \texttt{setValue} method previously defined is only beneficial when combined with \texttt{receiveMessage}; the latter handles messages sent to the input, and these are generally sent from the server via functions the likes of \texttt{updateSelectInput}. Internally it uses the \texttt{setValue} method to define the value of the input received from the server. Note that the \texttt{value} is, therefore, a serialised\index{serialise} JSON\index{JSON} input coming from the R server and can be of any complexity you desire. Below we use it such that it expects a simple boolean as the checkbox (switch) can be either on (\texttt{true}) or off (\texttt{false}).

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{var}\NormalTok{ switchInput }\OperatorTok{=} \KeywordTok{new} \VariableTok{Shiny}\NormalTok{.}\AttributeTok{InputBinding}\NormalTok{()}\OperatorTok{;}

\VariableTok{$}\NormalTok{.}\AttributeTok{extend}\NormalTok{(switchInput}\OperatorTok{,} \OperatorTok{\{}
  \DataTypeTok{find}\OperatorTok{:} \KeywordTok{function}\NormalTok{(scope) }\OperatorTok{\{}
    \ControlFlowTok{return} \AttributeTok{$}\NormalTok{(scope).}\AttributeTok{find}\NormalTok{(}\StringTok{".switchInput"}\NormalTok{)}\OperatorTok{;}
  \OperatorTok{\},}
  \DataTypeTok{getValue}\OperatorTok{:} \KeywordTok{function}\NormalTok{(el) }\OperatorTok{\{}
    \ControlFlowTok{return} \AttributeTok{$}\NormalTok{(el).}\AttributeTok{prop}\NormalTok{(}\StringTok{"checked"}\NormalTok{)}\OperatorTok{;}
  \OperatorTok{\},}
  \DataTypeTok{setValue}\OperatorTok{:} \KeywordTok{function}\NormalTok{(el}\OperatorTok{,}\NormalTok{ value) }\OperatorTok{\{}
    \AttributeTok{$}\NormalTok{(el).}\AttributeTok{prop}\NormalTok{(}\StringTok{"checked"}\OperatorTok{,}\NormalTok{ value).}\AttributeTok{change}\NormalTok{()}\OperatorTok{;}
  \OperatorTok{\},}
  \CommentTok{// handle messages from the server}
  \DataTypeTok{receiveMessage}\OperatorTok{:} \KeywordTok{function}\NormalTok{(el}\OperatorTok{,}\NormalTok{ value)}\OperatorTok{\{}
    \KeywordTok{this}\NormalTok{.}\AttributeTok{setValue}\NormalTok{(el}\OperatorTok{,}\NormalTok{ value)}\OperatorTok{;}
  \OperatorTok{\}}
\OperatorTok{\}}\NormalTok{)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

\hypertarget{shiny-input-sub-unsub}{%
\subsection{Subscribe and Unsubscribe Inputs}\label{shiny-input-sub-unsub}}

Finally, a crucial method is \texttt{subscribe}. This is run when the input is registered (more on that later) and is used to determine when Shiny sends new values of the input back to the server. This method also accepts a \texttt{callback}, which is the same function that tells Shiny to update the value. This callback function accepts a single boolean value, which the \href{https://github.com/rstudio/shiny/blob/master/srcjs/input_binding.js\#L18}{source code} states is used to enable debouncing or throttling. This is covered in the next section on rate policy.

This method often consists of an event listener that observes changes on the input to send it to the server. In layman terms, when the switch input changes (on to off or vice versa) run the \texttt{callback} function, which sends the data to the server.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{var}\NormalTok{ switchInput }\OperatorTok{=} \KeywordTok{new} \VariableTok{Shiny}\NormalTok{.}\AttributeTok{InputBinding}\NormalTok{()}\OperatorTok{;}

\VariableTok{$}\NormalTok{.}\AttributeTok{extend}\NormalTok{(switchInput}\OperatorTok{,} \OperatorTok{\{}
  \DataTypeTok{find}\OperatorTok{:} \KeywordTok{function}\NormalTok{(scope) }\OperatorTok{\{}
    \ControlFlowTok{return} \AttributeTok{$}\NormalTok{(scope).}\AttributeTok{find}\NormalTok{(}\StringTok{".switchInput"}\NormalTok{)}\OperatorTok{;}
  \OperatorTok{\},}
  \DataTypeTok{getValue}\OperatorTok{:} \KeywordTok{function}\NormalTok{(el) }\OperatorTok{\{}
    \ControlFlowTok{return} \AttributeTok{$}\NormalTok{(el).}\AttributeTok{prop}\NormalTok{(}\StringTok{"checked"}\NormalTok{)}\OperatorTok{;}
  \OperatorTok{\},}
  \DataTypeTok{setValue}\OperatorTok{:} \KeywordTok{function}\NormalTok{(el}\OperatorTok{,}\NormalTok{ value) }\OperatorTok{\{}
    \AttributeTok{$}\NormalTok{(el).}\AttributeTok{prop}\NormalTok{(}\StringTok{"checked"}\OperatorTok{,}\NormalTok{ value).}\AttributeTok{change}\NormalTok{()}\OperatorTok{;}
  \OperatorTok{\},}
  \DataTypeTok{receiveMessage}\OperatorTok{:} \KeywordTok{function}\NormalTok{(el}\OperatorTok{,}\NormalTok{ value)}\OperatorTok{\{}
    \KeywordTok{this}\NormalTok{.}\AttributeTok{setValue}\NormalTok{(el}\OperatorTok{,}\NormalTok{ value)}\OperatorTok{;}
  \OperatorTok{\},}
  \DataTypeTok{subscribe}\OperatorTok{:} \KeywordTok{function}\NormalTok{ (el}\OperatorTok{,}\NormalTok{ callback) }\OperatorTok{\{}
    \AttributeTok{$}\NormalTok{(el).}\AttributeTok{on}\NormalTok{(}\StringTok{"change.switchInput"}\OperatorTok{,} \KeywordTok{function}\NormalTok{()}\OperatorTok{\{}
      \AttributeTok{callback}\NormalTok{(}\KeywordTok{true}\NormalTok{)}\OperatorTok{;}
    \OperatorTok{\}}\NormalTok{)}
  \OperatorTok{\},}
  \DataTypeTok{unsubscribe}\OperatorTok{:} \KeywordTok{function}\NormalTok{(el) }\OperatorTok{\{}
    \AttributeTok{$}\NormalTok{(el).}\AttributeTok{off}\NormalTok{(}\StringTok{".switchInput"}\NormalTok{)}\OperatorTok{;}
  \OperatorTok{\}}
\OperatorTok{\}}\NormalTok{)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

Note that in the \texttt{subscribe} method we listen for \texttt{change}s on the input; hence the \texttt{setValue} also uses jQuery's \texttt{change} method; it ensures this event is fired and that Shiny will subsequently pick it up.

\begin{rmdnote}
Make sure the \texttt{setValue} method triggers the event observed in
\texttt{subscribe}
\end{rmdnote}

\hypertarget{shiny-input-rate-policy}{%
\subsection{Input Rate Policy}\label{shiny-input-rate-policy}}

The rate policy determines how frequently the binding should send new input values back to the server. The \texttt{getRatePolicy} method should return an object that describes a JSON array with two variables: \texttt{policy} and \texttt{delay}.

\textbf{direct}

The \texttt{direct} policy tells Shiny to sends any new value directly, however often this occurs. Therefore, this policy does not make use of \texttt{delay}.

\begin{Shaded}
\begin{Highlighting}[]
\FunctionTok{\{}
  \ErrorTok{policy}\FunctionTok{:} \StringTok{"direct"}
\FunctionTok{\}}
\end{Highlighting}
\end{Shaded}

\textbf{debounce}

The \texttt{debounce} policy tells Shiny to ignore all new values until no new values have been received for \texttt{delay} milliseconds.

\begin{Shaded}
\begin{Highlighting}[]
\FunctionTok{\{}
  \ErrorTok{policy}\FunctionTok{:} \StringTok{"debounce"}\FunctionTok{,}
  \ErrorTok{delay}\FunctionTok{:} \DecValTok{2500}
\FunctionTok{\}}
\end{Highlighting}
\end{Shaded}

\textbf{throttle}

The \texttt{throttle} policy means that no more than one value will be sent per \texttt{delay} milliseconds.

\begin{Shaded}
\begin{Highlighting}[]
\FunctionTok{\{}
  \ErrorTok{policy}\FunctionTok{:} \StringTok{"throttle"}\FunctionTok{,}
  \ErrorTok{delay}\FunctionTok{:} \DecValTok{1000}
\FunctionTok{\}}
\end{Highlighting}
\end{Shaded}

A switch input is not expected to change frequently, but it's nonetheless good practice to throttle it to ensure the server does not receive too many requests. This will admittedly be more relevant to inputs that see a higher rate of change like text fields, which unless debounced send every keystroke to the server.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{var}\NormalTok{ switchInput }\OperatorTok{=} \KeywordTok{new} \VariableTok{Shiny}\NormalTok{.}\AttributeTok{InputBinding}\NormalTok{()}\OperatorTok{;}

\VariableTok{$}\NormalTok{.}\AttributeTok{extend}\NormalTok{(switchInput}\OperatorTok{,} \OperatorTok{\{}
  \DataTypeTok{find}\OperatorTok{:} \KeywordTok{function}\NormalTok{(scope) }\OperatorTok{\{}
    \ControlFlowTok{return} \AttributeTok{$}\NormalTok{(scope).}\AttributeTok{find}\NormalTok{(}\StringTok{".switchInput"}\NormalTok{)}\OperatorTok{;}
  \OperatorTok{\},}
  \DataTypeTok{getValue}\OperatorTok{:} \KeywordTok{function}\NormalTok{(el) }\OperatorTok{\{}
    \ControlFlowTok{return} \AttributeTok{$}\NormalTok{(el).}\AttributeTok{prop}\NormalTok{(}\StringTok{"checked"}\NormalTok{)}\OperatorTok{;}
  \OperatorTok{\},}
  \DataTypeTok{setValue}\OperatorTok{:} \KeywordTok{function}\NormalTok{(el}\OperatorTok{,}\NormalTok{ value) }\OperatorTok{\{}
    \AttributeTok{$}\NormalTok{(el).}\AttributeTok{prop}\NormalTok{(}\StringTok{"checked"}\OperatorTok{,}\NormalTok{ value).}\AttributeTok{change}\NormalTok{()}\OperatorTok{;}
  \OperatorTok{\},}
  \DataTypeTok{receiveMessage}\OperatorTok{:} \KeywordTok{function}\NormalTok{(el}\OperatorTok{,}\NormalTok{ value)}\OperatorTok{\{}
    \KeywordTok{this}\NormalTok{.}\AttributeTok{setValue}\NormalTok{(el}\OperatorTok{,}\NormalTok{ value)}\OperatorTok{;}
  \OperatorTok{\},}
  \DataTypeTok{subscribe}\OperatorTok{:} \KeywordTok{function}\NormalTok{ (el}\OperatorTok{,}\NormalTok{ callback) }\OperatorTok{\{}
    \AttributeTok{$}\NormalTok{(el).}\AttributeTok{on}\NormalTok{(}\StringTok{"change.switchInput"}\OperatorTok{,} \KeywordTok{function}\NormalTok{()}\OperatorTok{\{}
      \AttributeTok{callback}\NormalTok{(}\KeywordTok{true}\NormalTok{)}\OperatorTok{;}
    \OperatorTok{\}}\NormalTok{)}
  \OperatorTok{\},}
  \DataTypeTok{unsubscribe}\OperatorTok{:} \KeywordTok{function}\NormalTok{(el) }\OperatorTok{\{}
    \AttributeTok{$}\NormalTok{(el).}\AttributeTok{off}\NormalTok{(}\StringTok{".switchInput"}\NormalTok{)}\OperatorTok{;}
  \OperatorTok{\},}
  \CommentTok{// throttle}
  \DataTypeTok{getRatePolicy}\OperatorTok{:} \KeywordTok{function}\NormalTok{()}\OperatorTok{\{}
    \ControlFlowTok{return} \OperatorTok{\{}
      \DataTypeTok{policy}\OperatorTok{:} \StringTok{'throttle'}\OperatorTok{,}
      \DataTypeTok{delay}\OperatorTok{:} \DecValTok{1000}
    \OperatorTok{\}}
  \OperatorTok{\}}
\OperatorTok{\}}\NormalTok{)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

\hypertarget{shiny-input-register}{%
\subsection{Registering the Input Binding}\label{shiny-input-register}}

Finally, like the custom output, the input can be registered with Shiny. It too takes a unique identifier as a second argument.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{var}\NormalTok{ switchInput }\OperatorTok{=} \KeywordTok{new} \VariableTok{Shiny}\NormalTok{.}\AttributeTok{InputBinding}\NormalTok{()}\OperatorTok{;}

\VariableTok{$}\NormalTok{.}\AttributeTok{extend}\NormalTok{(switchInput}\OperatorTok{,} \OperatorTok{\{}
  \DataTypeTok{find}\OperatorTok{:} \KeywordTok{function}\NormalTok{(scope) }\OperatorTok{\{}
    \ControlFlowTok{return} \AttributeTok{$}\NormalTok{(scope).}\AttributeTok{find}\NormalTok{(}\StringTok{".switchInput"}\NormalTok{)}\OperatorTok{;}
  \OperatorTok{\},}
  \DataTypeTok{getValue}\OperatorTok{:} \KeywordTok{function}\NormalTok{(el) }\OperatorTok{\{}
    \ControlFlowTok{return} \AttributeTok{$}\NormalTok{(el).}\AttributeTok{prop}\NormalTok{(}\StringTok{"checked"}\NormalTok{)}\OperatorTok{;}
  \OperatorTok{\},}
  \DataTypeTok{setValue}\OperatorTok{:} \KeywordTok{function}\NormalTok{(el}\OperatorTok{,}\NormalTok{ value) }\OperatorTok{\{}
    \AttributeTok{$}\NormalTok{(el).}\AttributeTok{prop}\NormalTok{(}\StringTok{"checked"}\OperatorTok{,}\NormalTok{ value).}\AttributeTok{change}\NormalTok{()}\OperatorTok{;}
  \OperatorTok{\},}
  \DataTypeTok{receiveMessage}\OperatorTok{:} \KeywordTok{function}\NormalTok{(el}\OperatorTok{,}\NormalTok{ value)}\OperatorTok{\{}
    \KeywordTok{this}\NormalTok{.}\AttributeTok{setValue}\NormalTok{(el}\OperatorTok{,}\NormalTok{ value)}\OperatorTok{;}
  \OperatorTok{\},}
  \DataTypeTok{subscribe}\OperatorTok{:} \KeywordTok{function}\NormalTok{ (el}\OperatorTok{,}\NormalTok{ callback) }\OperatorTok{\{}
    \AttributeTok{$}\NormalTok{(el).}\AttributeTok{on}\NormalTok{(}\StringTok{"change.switchInput"}\OperatorTok{,} \KeywordTok{function}\NormalTok{()}\OperatorTok{\{}
      \AttributeTok{callback}\NormalTok{(}\KeywordTok{true}\NormalTok{)}\OperatorTok{;}
    \OperatorTok{\}}\NormalTok{)}
  \OperatorTok{\},}
  \DataTypeTok{unsubscribe}\OperatorTok{:} \KeywordTok{function}\NormalTok{(el) }\OperatorTok{\{}
    \AttributeTok{$}\NormalTok{(el).}\AttributeTok{off}\NormalTok{(}\StringTok{".switchInput"}\NormalTok{)}\OperatorTok{;}
  \OperatorTok{\},}
  \DataTypeTok{getRatePolicy}\OperatorTok{:} \KeywordTok{function}\NormalTok{()}\OperatorTok{\{}
    \ControlFlowTok{return} \OperatorTok{\{}
      \DataTypeTok{policy}\OperatorTok{:} \StringTok{'throttle'}\OperatorTok{,}
      \DataTypeTok{delay}\OperatorTok{:} \DecValTok{1000}
    \OperatorTok{\}}
  \OperatorTok{\}}
\OperatorTok{\}}\NormalTok{)}\OperatorTok{;}

\VariableTok{Shiny}\NormalTok{.}\VariableTok{inputBindings}\NormalTok{.}\AttributeTok{register}\NormalTok{(switchInput}\OperatorTok{,} \StringTok{'john.switch'}\NormalTok{)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

This wraps up a custom input: it can now be used in a shiny application (see Figure \ref{fig:switch-example}).

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(shiny)}

\NormalTok{ui <-}\StringTok{ }\KeywordTok{fluidPage}\NormalTok{(}
  \KeywordTok{switchInput}\NormalTok{(}\StringTok{"switch"}\NormalTok{, }\StringTok{"Show plot"}\NormalTok{, }\OtherTok{FALSE}\NormalTok{),}
  \KeywordTok{plotOutput}\NormalTok{(}\StringTok{"plot"}\NormalTok{)}
\NormalTok{)}

\NormalTok{server <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(input, output, session)\{}

\NormalTok{  output}\OperatorTok{$}\NormalTok{plot <-}\StringTok{ }\KeywordTok{renderPlot}\NormalTok{(\{}
    \KeywordTok{print}\NormalTok{(input}\OperatorTok{$}\ControlFlowTok{switch}\NormalTok{)}

    \ControlFlowTok{if}\NormalTok{(}\OperatorTok{!}\NormalTok{input}\OperatorTok{$}\ControlFlowTok{switch}\NormalTok{)}
      \KeywordTok{return}\NormalTok{()}

    \KeywordTok{plot}\NormalTok{(cars)}
\NormalTok{  \})}
\NormalTok{\}}

\KeywordTok{shinyApp}\NormalTok{(ui, server)}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/switch-example} 

}

\caption{Switch input example}\label{fig:switch-example}
\end{figure}

\hypertarget{shiny-input-update}{%
\section{Update Input}\label{shiny-input-update}}

The JavaScript binding was provided with the required methods to receive updates from the server to change the value of the switch input, but the R function that sends those updates is yet to be written.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{update_switch_input <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(id, value, }
  \DataTypeTok{session =}\NormalTok{ shiny}\OperatorTok{::}\KeywordTok{getDefaultReactiveDomain}\NormalTok{())\{}
\NormalTok{  session}\OperatorTok{$}\KeywordTok{sendInputMessage}\NormalTok{(id, value)}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

This pattern was used previously, albeit using \texttt{sendCustomMessage}; with \texttt{sendInputMessage} the message can be sent straight to the \texttt{receiveMessage} handler of the input using 1) the \texttt{id} of the input and 2) the data one wants to send.

We can adapt the application to use this button.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(shiny)}

\NormalTok{ui <-}\StringTok{ }\KeywordTok{fluidPage}\NormalTok{(}
  \KeywordTok{actionButton}\NormalTok{(}\StringTok{"chg"}\NormalTok{, }\StringTok{"Switch ON"}\NormalTok{),}
  \KeywordTok{switchInput}\NormalTok{(}\StringTok{"switch"}\NormalTok{, }\StringTok{"Switch input"}\NormalTok{, }\OtherTok{FALSE}\NormalTok{),}
  \KeywordTok{plotOutput}\NormalTok{(}\StringTok{"plot"}\NormalTok{)}
\NormalTok{)}

\NormalTok{server <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(input, output, session)\{}

\NormalTok{  output}\OperatorTok{$}\NormalTok{plot <-}\StringTok{ }\KeywordTok{renderPlot}\NormalTok{(\{}
    \KeywordTok{print}\NormalTok{(input}\OperatorTok{$}\ControlFlowTok{switch}\NormalTok{)}
    
    \ControlFlowTok{if}\NormalTok{(}\OperatorTok{!}\NormalTok{input}\OperatorTok{$}\ControlFlowTok{switch}\NormalTok{)}
      \KeywordTok{return}\NormalTok{()}

    \KeywordTok{plot}\NormalTok{(cars)}
\NormalTok{  \})}

  \KeywordTok{observeEvent}\NormalTok{(input}\OperatorTok{$}\NormalTok{chg, \{}
    \KeywordTok{update_switch_input}\NormalTok{(}\StringTok{"switch"}\NormalTok{, }\OtherTok{TRUE}\NormalTok{, session)}
\NormalTok{  \})}
\NormalTok{\}}

\KeywordTok{shinyApp}\NormalTok{(ui, server)}
\end{Highlighting}
\end{Shaded}

Figure \ref{fig:shiny-input-diagram} attempts to summarize the various elements that were put together and used in the last application.

It all starts from the \texttt{switchInput} function, which generates the HTML\index{HTML} defining the switch input and its initial state. In the \texttt{subscribe} method, an event listener checks for changes on this HTML element (\texttt{\$(el).on(\textquotesingle{}change\textquotesingle{},\ ...)}). Every time it changes (check/uncheck) it fires the Shiny \texttt{callback}, which sends the value of the input obtained from \texttt{getValue} through the WebSocket\index{WebSocket}. When the value of the input is changed from the server this value travels through the WebSocket\index{WebSocket} to the front end, where \texttt{receiveMessage} uses \texttt{setValue} to programmatically change the check-box, which incidentally triggers the change event, and back we go.

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/04-shiny-input} 

}

\caption{Shiny input visualised}\label{fig:shiny-input-diagram}
\end{figure}

If you wish to explore Shiny inputs in more depth I suggests reading David Granjon's book: \emph{\href{https://unleash-shiny.rinterface.com/}{Outstanding Shiny UI.}}

\hypertarget{shiny-input-excercise}{%
\section{Exercise}\label{shiny-input-excercise}}

\begin{itemize}
\tightlist
\item
  Add a \texttt{toggle\_switch\_input} function that toggles between states so it turns it off when it's on and vice versa
\item
  Bring support for \href{https://getbootstrap.com/docs/3.3/components/\#input-groups-basic}{Bootstrap 3 text input addon}
\end{itemize}

\hypertarget{shiny-cookies}{%
\chapter{Cookies}\label{shiny-cookies}}

In this chapter, we scout yet another excellent example of how JavaScript can enhance Shiny applications. We use an HTTP cookie, a small piece of data sent from an application and stored in the user's web browser\index{web browser}, to track users returning to a Shiny application.

The application will prompt users to input their name; this will be stored in a cookie so that on their next visit, they are welcomed to the app with a personalised message. Cookies are natively supported by web browsers and JavaScript, though we will use a library which greatly eases their handling: \href{https://github.com/js-cookie/js-cookie}{js-cookie}.

\hypertarget{shiny-cookies-discover}{%
\section{Discover js-cookie}\label{shiny-cookies-discover}}

The library is at its core very straightforward; it exports\index{export} a \texttt{Cookie} object from which one can access the \texttt{set}, \texttt{get}, and \texttt{remove} methods.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{// set a cookie}
\VariableTok{Cookies}\NormalTok{.}\AttributeTok{set}\NormalTok{(}\StringTok{'name'}\OperatorTok{,} \StringTok{'value'}\NormalTok{)}

\CommentTok{// get cookies}
\VariableTok{Cookies}\NormalTok{.}\AttributeTok{get}\NormalTok{()}\OperatorTok{;}

\CommentTok{// remove a cookie}
\VariableTok{Cookies}\NormalTok{.}\AttributeTok{remove}\NormalTok{(}\StringTok{'name'}\NormalTok{)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

There is also the possibility to pass additional options when defining the cookie, such as how long it is valid for, but we won't explore these here.

\hypertarget{shiny-cookies-setup}{%
\section{Setup Project}\label{shiny-cookies-setup}}

Then again, it starts with the creation of a directory where we'll place a JavaScript file containing the message handlers; we won't download the dependency\index{dependency} and use the CDN\index{CDN} instead but feel free to do differently.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{dir.create}\NormalTok{(}\StringTok{"www"}\NormalTok{)}
\KeywordTok{file.create}\NormalTok{(}\StringTok{"www/script.js"}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

We then lay down the skeleton of the application which features a text input to capture the name of the user, a button to save the cookie in their browsers, another to remove it and finally a dynamic output that will display the personalised message.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(shiny)}

\KeywordTok{addResourcePath}\NormalTok{(}\StringTok{"www"}\NormalTok{, }\StringTok{"www"}\NormalTok{)}

\NormalTok{ui <-}\StringTok{ }\KeywordTok{fluidPage}\NormalTok{(}
\NormalTok{  tags}\OperatorTok{$}\KeywordTok{head}\NormalTok{(}
\NormalTok{    tags}\OperatorTok{$}\KeywordTok{script}\NormalTok{(}
      \DataTypeTok{src =} \KeywordTok{paste0}\NormalTok{(}
        \StringTok{"https://cdn.jsdelivr.net/npm/js-cookie@rc/"}\NormalTok{,}
        \StringTok{"dist/js.cookie.min.js"}
\NormalTok{      )}
\NormalTok{    ),}
\NormalTok{    tags}\OperatorTok{$}\KeywordTok{script}\NormalTok{(}\DataTypeTok{src =} \StringTok{"www/script.js"}\NormalTok{)}
\NormalTok{  ),}
  \KeywordTok{textInput}\NormalTok{(}\StringTok{"name_set"}\NormalTok{, }\StringTok{"What is your name?"}\NormalTok{),}
  \KeywordTok{actionButton}\NormalTok{(}\StringTok{"save"}\NormalTok{, }\StringTok{"Save cookie"}\NormalTok{),}
  \KeywordTok{actionButton}\NormalTok{(}\StringTok{"remove"}\NormalTok{, }\StringTok{"remove cookie"}\NormalTok{),}
  \KeywordTok{uiOutput}\NormalTok{(}\StringTok{"name_get"}\NormalTok{)}
\NormalTok{)}

\NormalTok{server <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(input, output, session)\{}

\NormalTok{\}}

\KeywordTok{shinyApp}\NormalTok{(ui, server)}
\end{Highlighting}
\end{Shaded}

\hypertarget{shiny-cookies-javascript}{%
\section{JavaScript Cookies}\label{shiny-cookies-javascript}}

First, we define a JavaScript function that retrieves the cookies and sets the result as an input named \texttt{cookies}. The reason we do so is because we will have to execute this in multiple places; this will become clearer in just a second.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{// script.js}
\KeywordTok{function} \AttributeTok{getCookies}\NormalTok{()}\OperatorTok{\{}
  \KeywordTok{var}\NormalTok{ res }\OperatorTok{=} \VariableTok{Cookies}\NormalTok{.}\AttributeTok{get}\NormalTok{()}\OperatorTok{;}
  \VariableTok{Shiny}\NormalTok{.}\AttributeTok{setInputValue}\NormalTok{(}\StringTok{'cookies'}\OperatorTok{,}\NormalTok{ res)}\OperatorTok{;}
\OperatorTok{\}}
\end{Highlighting}
\end{Shaded}

Then we define two message handlers, one that sets the cookie and another that removes it. Note that both of them run the \texttt{getCookies} function defined previously after they are done with their respective operations. The reason this is done is that we need the input to be updated with the new values after it is set and after it is removed. Otherwise setting or removing the cookie will leave the actual input value untouched and the result of the operation (setting or removing the cookie) will not be captured server-side.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{// script.js}
\VariableTok{Shiny}\NormalTok{.}\AttributeTok{addCustomMessageHandler}\NormalTok{(}\StringTok{'cookie-set'}\OperatorTok{,} \KeywordTok{function}\NormalTok{(msg)}\OperatorTok{\{}
  \VariableTok{Cookies}\NormalTok{.}\AttributeTok{set}\NormalTok{(}\VariableTok{msg}\NormalTok{.}\AttributeTok{name}\OperatorTok{,} \VariableTok{msg}\NormalTok{.}\AttributeTok{value}\NormalTok{)}\OperatorTok{;}
  \AttributeTok{getCookies}\NormalTok{()}\OperatorTok{;}
\OperatorTok{\}}\NormalTok{)}

\VariableTok{Shiny}\NormalTok{.}\AttributeTok{addCustomMessageHandler}\NormalTok{(}\StringTok{'cookie-remove'}\OperatorTok{,} \KeywordTok{function}\NormalTok{(msg)}\OperatorTok{\{}
  \VariableTok{Cookies}\NormalTok{.}\AttributeTok{remove}\NormalTok{(}\VariableTok{msg}\NormalTok{.}\AttributeTok{name}\NormalTok{)}\OperatorTok{;}
  \AttributeTok{getCookies}\NormalTok{()}\OperatorTok{;}
\OperatorTok{\}}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

One more thing needs to be implemented JavaScript-side. The point of using the cookie is that when users come back to the Shiny app, even days later, they are presented with the personalised welcome message, this implies that when they open the application, the input value is defined. Therefore, \texttt{getCookies} must at launch. One could be tempted to place it at the top of the JavaScript file so that it runs when it is imported but the issue there is that it will run too soon, it will run the Shiny input is not yet available and fail to set it. Consequently, we instead observe the \texttt{shiny:connected} event, which is fired when the initial connection to the server is established.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{// script.js}
\AttributeTok{$}\NormalTok{(document).}\AttributeTok{on}\NormalTok{(}\StringTok{'shiny:connected'}\OperatorTok{,} \KeywordTok{function}\NormalTok{(ev)}\OperatorTok{\{}
  \AttributeTok{getCookies}\NormalTok{()}\OperatorTok{;}
\OperatorTok{\}}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

\hypertarget{shiny-cookies-r-code}{%
\section{R Code}\label{shiny-cookies-r-code}}

Then it's a matter of completing the Shiny server which was left empty. We add an \texttt{observeEvent} on the save button where we check that a name has actually been typed in the text box before saving the cookie. There is another similar observer on the remove button. The \texttt{renderUI} expression checks that the cookie has been set and displays a message accordingly.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(shiny)}

\KeywordTok{addResourcePath}\NormalTok{(}\StringTok{"www"}\NormalTok{, }\StringTok{"www"}\NormalTok{)}

\NormalTok{ui <-}\StringTok{ }\KeywordTok{fluidPage}\NormalTok{(}
\NormalTok{  tags}\OperatorTok{$}\KeywordTok{head}\NormalTok{(}
\NormalTok{    tags}\OperatorTok{$}\KeywordTok{script}\NormalTok{(}
      \DataTypeTok{src =} \KeywordTok{paste0}\NormalTok{(}
        \StringTok{"https://cdn.jsdelivr.net/npm/js-cookie@rc/"}\NormalTok{,}
        \StringTok{"dist/js.cookie.min.js"}
\NormalTok{      )}
\NormalTok{    ),}
\NormalTok{    tags}\OperatorTok{$}\KeywordTok{script}\NormalTok{(}\DataTypeTok{src =} \StringTok{"www/script.js"}\NormalTok{)}
\NormalTok{  ),}
  \KeywordTok{textInput}\NormalTok{(}\StringTok{"name_set"}\NormalTok{, }\StringTok{"What is your name?"}\NormalTok{),}
  \KeywordTok{actionButton}\NormalTok{(}\StringTok{"save"}\NormalTok{, }\StringTok{"Save cookie"}\NormalTok{),}
  \KeywordTok{actionButton}\NormalTok{(}\StringTok{"remove"}\NormalTok{, }\StringTok{"remove cookie"}\NormalTok{),}
  \KeywordTok{uiOutput}\NormalTok{(}\StringTok{"name_get"}\NormalTok{)}
\NormalTok{)}

\NormalTok{server <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(input, output, session)\{}

  \CommentTok{# save}
  \KeywordTok{observeEvent}\NormalTok{(input}\OperatorTok{$}\NormalTok{save, \{}
\NormalTok{    msg <-}\StringTok{ }\KeywordTok{list}\NormalTok{(}
      \DataTypeTok{name =} \StringTok{"name"}\NormalTok{, }\DataTypeTok{value =}\NormalTok{ input}\OperatorTok{$}\NormalTok{name_set}
\NormalTok{    )}

    \ControlFlowTok{if}\NormalTok{(input}\OperatorTok{$}\NormalTok{name_set }\OperatorTok{!=}\StringTok{ ""}\NormalTok{)}
\NormalTok{      session}\OperatorTok{$}\KeywordTok{sendCustomMessage}\NormalTok{(}\StringTok{"cookie-set"}\NormalTok{, msg)}
\NormalTok{  \})}

  \CommentTok{# delete}
  \KeywordTok{observeEvent}\NormalTok{(input}\OperatorTok{$}\NormalTok{remove, \{}
\NormalTok{    msg <-}\StringTok{ }\KeywordTok{list}\NormalTok{(}\DataTypeTok{name =} \StringTok{"name"}\NormalTok{)}
\NormalTok{    session}\OperatorTok{$}\KeywordTok{sendCustomMessage}\NormalTok{(}\StringTok{"cookie-remove"}\NormalTok{, msg)}
\NormalTok{  \})}

  \CommentTok{# output if cookie is specified}
\NormalTok{  output}\OperatorTok{$}\NormalTok{name_get <-}\StringTok{ }\KeywordTok{renderUI}\NormalTok{(\{}
    \ControlFlowTok{if}\NormalTok{(}\OperatorTok{!}\KeywordTok{is.null}\NormalTok{(input}\OperatorTok{$}\NormalTok{cookies}\OperatorTok{$}\NormalTok{name))}
      \KeywordTok{h3}\NormalTok{(}\StringTok{"Hello,"}\NormalTok{, input}\OperatorTok{$}\NormalTok{cookies}\OperatorTok{$}\NormalTok{name)}
    \ControlFlowTok{else}
      \KeywordTok{h3}\NormalTok{(}\StringTok{"Who are you?"}\NormalTok{)}
\NormalTok{  \})}

\NormalTok{\}}

\KeywordTok{shinyApp}\NormalTok{(ui, server)}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/shiny-cookies-2} 

}

\caption{Shiny using cookies}\label{fig:shiny-cookies}
\end{figure}

Run the application and save your name. You can then refresh the application, and the welcome message will display your name. You can even kill the server entirely and re-run the app; the welcome message will still display as in Figure \ref{fig:shiny-cookies}!

\hypertarget{shiny-cookies-exercises}{%
\section{Exercises}\label{shiny-cookies-exercises}}

In the following chapter, we cover the use of Shiny and bidirectional specifically for htmlwidgets. Before moving on it is a good idea to attempt to replicate the examples that were created in this part of the book. Below are some interesting JavaScript libraries that are not yet integrated with Shiny (as packages). These would be great additions to the Shiny ecosystem and are specifically selected because they are approachable.

\begin{itemize}
\tightlist
\item
  \href{https://github.com/Ghosh/micromodal}{micromodal.js} - tiny, dependency-free javascript library for creating accessible modals
\item
  \href{https://github.com/jaywcjlove/hotkeys}{hotkeys} - capture keyboard inputs
\item
  \href{https://github.com/victordibia/handtrack.js}{handtrack.js} - realtime hand detection
\item
  \href{https://github.com/TalAter/annyang}{annyang} - speech Recognition library
\end{itemize}

\hypertarget{shiny-widgets}{%
\chapter{Widgets with Shiny}\label{shiny-widgets}}

We have seen how to make JavaScript and R communicate in Shiny applications by passing data from the server to the client and back. This chapter explores how to apply that to htmlwidgets so they can provide additional functionalities when used in Shiny applications.

To demonstrate how to integrate these functionalities in widgets, we shall implement them in the previously built gio package.

\hypertarget{shiny-widgets-to-r}{%
\section{Widgets to R}\label{shiny-widgets-to-r}}

In a previous chapter on \protect\hyperlink{linking-widgets}{Linking Widgets}, the topic of callback function was briefly explored. Gio.js provides a callback function that is fired every time a country is selected on globe; this is currently used to share said country with other widgets as part of the implementation with crosstalk. This callback function could also send data back to the R server where they could be used for many things like fetching more data on the selected country from a database or use that information to generate a Shiny UI element like displaying the flag of the selected country, and much, much more.

The callback function in the gio package currently looks like this; it only makes use of some of the data for crosstalk.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{// define callback function}
\KeywordTok{function} \AttributeTok{callback}\NormalTok{ (selectedCountry}\OperatorTok{,}\NormalTok{ relatedCountries) }\OperatorTok{\{}
  \VariableTok{sel_handle}\NormalTok{.}\AttributeTok{set}\NormalTok{([}\VariableTok{selectedCountry}\NormalTok{.}\AttributeTok{ISOCode}\NormalTok{])}\OperatorTok{;}
\OperatorTok{\}}

\CommentTok{// use callback function}
\VariableTok{controller}\NormalTok{.}\AttributeTok{onCountryPicked}\NormalTok{(callback)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

We can make further use of this to define two different Shiny inputs; one for the selected country and another for its related edges.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{// gio.js}
\CommentTok{// define callback function}
\KeywordTok{function} \AttributeTok{callback}\NormalTok{ (selectedCountry}\OperatorTok{,}\NormalTok{ relatedCountries) }\OperatorTok{\{}
  \VariableTok{sel_handle}\NormalTok{.}\AttributeTok{set}\NormalTok{([}\VariableTok{selectedCountry}\NormalTok{.}\AttributeTok{ISOCode}\NormalTok{])}\OperatorTok{;}
  \VariableTok{Shiny}\NormalTok{.}\AttributeTok{setInputValue}\NormalTok{(}\StringTok{'selected'}\OperatorTok{,}\NormalTok{ selectedCountry)}\OperatorTok{;}
  \VariableTok{Shiny}\NormalTok{.}\AttributeTok{setInputValue}\NormalTok{(}\StringTok{'related'}\OperatorTok{,}\NormalTok{ relatedCountries)}\OperatorTok{;}
\OperatorTok{\}}
\end{Highlighting}
\end{Shaded}

However, this will generate an issue experienced in a previous chapter; multiple gio visualisations in a single Shiny application would be defining the values of a single input. This can be remedied to by using the id of the visualisation\index{visualisation} to generate the input name dynamically.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{renderValue}\OperatorTok{:} \KeywordTok{function}\NormalTok{(x) }\OperatorTok{\{}

  \KeywordTok{var}\NormalTok{ controller }\OperatorTok{=} \KeywordTok{new} \VariableTok{GIO}\NormalTok{.}\AttributeTok{Controller}\NormalTok{(el)}\OperatorTok{;}
  \VariableTok{controller}\NormalTok{.}\AttributeTok{addData}\NormalTok{(}\VariableTok{x}\NormalTok{.}\AttributeTok{data}\NormalTok{)}\OperatorTok{;}
  \VariableTok{controller}\NormalTok{.}\AttributeTok{setStyle}\NormalTok{(}\VariableTok{x}\NormalTok{.}\AttributeTok{style}\NormalTok{)}\OperatorTok{;}

  \CommentTok{// callback}
  \KeywordTok{function} \AttributeTok{callback}\NormalTok{ (selectedCountry}\OperatorTok{,}\NormalTok{ relatedCountries) }\OperatorTok{\{}
    \VariableTok{sel_handle}\NormalTok{.}\AttributeTok{set}\NormalTok{([}\VariableTok{selectedCountry}\NormalTok{.}\AttributeTok{ISOCode}\NormalTok{])}\OperatorTok{;}
    \VariableTok{Shiny}\NormalTok{.}\AttributeTok{setInputValue}\NormalTok{(}\VariableTok{el}\NormalTok{.}\AttributeTok{id} \OperatorTok{+} \StringTok{'_selected'}\OperatorTok{,}\NormalTok{ selectedCountry)}\OperatorTok{;}
    \VariableTok{Shiny}\NormalTok{.}\AttributeTok{setInputValue}\NormalTok{(}\VariableTok{el}\NormalTok{.}\AttributeTok{id} \OperatorTok{+} \StringTok{'_related'}\OperatorTok{,}\NormalTok{ relatedCountries)}\OperatorTok{;}
  \OperatorTok{\}}

  \VariableTok{controller}\NormalTok{.}\AttributeTok{onCountryPicked}\NormalTok{(callback)}\OperatorTok{;}

  \CommentTok{// render}
  \VariableTok{controller}\NormalTok{.}\AttributeTok{init}\NormalTok{()}\OperatorTok{;}

\OperatorTok{\}}
\end{Highlighting}
\end{Shaded}

The package can then be installed with \texttt{devtools::install} so we can test these inputs in a Shiny application (Figure \ref{fig:gio-shiny-no-handler}).

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(gio)}
\KeywordTok{library}\NormalTok{(shiny)}

\CommentTok{# large sample data}
\NormalTok{url <-}\StringTok{ }\KeywordTok{paste0}\NormalTok{(}
  \StringTok{"https://raw.githubusercontent.com/JohnCoene/"}\NormalTok{,}
  \StringTok{"javascript-for-r/master/data/countries.json"}
\NormalTok{)}
\NormalTok{arcs <-}\StringTok{ }\NormalTok{jsonlite}\OperatorTok{::}\KeywordTok{fromJSON}\NormalTok{(url)}

\NormalTok{ui <-}\StringTok{ }\KeywordTok{fluidPage}\NormalTok{(}
  \KeywordTok{gioOutput}\NormalTok{(}\StringTok{"globe"}\NormalTok{),}
  \KeywordTok{fluidRow}\NormalTok{(}
    \KeywordTok{column}\NormalTok{(}\DecValTok{6}\NormalTok{, }\KeywordTok{verbatimTextOutput}\NormalTok{(}\StringTok{"selectedCountry"}\NormalTok{)),}
    \KeywordTok{column}\NormalTok{(}\DecValTok{6}\NormalTok{, }\KeywordTok{verbatimTextOutput}\NormalTok{(}\StringTok{"relatedCountries"}\NormalTok{))}
\NormalTok{  )}
\NormalTok{)}

\NormalTok{server <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(input, output)\{}

\NormalTok{  output}\OperatorTok{$}\NormalTok{globe <-}\StringTok{ }\KeywordTok{renderGio}\NormalTok{(\{}
    \KeywordTok{gio}\NormalTok{(arcs, }\DataTypeTok{source =}\NormalTok{ i, }\DataTypeTok{target =}\NormalTok{ e, }\DataTypeTok{value =}\NormalTok{ v)}
\NormalTok{  \})}

\NormalTok{  output}\OperatorTok{$}\NormalTok{selectedCountry <-}\StringTok{ }\KeywordTok{renderPrint}\NormalTok{(\{}
    \KeywordTok{print}\NormalTok{(input}\OperatorTok{$}\NormalTok{globe_selected)}
\NormalTok{  \})}

\NormalTok{  output}\OperatorTok{$}\NormalTok{relatedCountries <-}\StringTok{ }\KeywordTok{renderPrint}\NormalTok{(\{}
    \KeywordTok{print}\NormalTok{(input}\OperatorTok{$}\NormalTok{globe_related)}
\NormalTok{  \})}

\NormalTok{\}}

\KeywordTok{shinyApp}\NormalTok{(ui, server)}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/gio-shiny-input-no-handler} 

}

\caption{Gio with input data}\label{fig:gio-shiny-no-handler}
\end{figure}

One thing to note before moving on, the data is sent from the client to the server whether the inputs are used or not, though this likely will not negatively impact gio it can reduce performances if the callback function is triggered too frequently. For instance, an input value set when the user hovers a scatter plot might lead to the event being fired very frequently and too much data being sent to the server, slowing things down and providing a poor experience.

Therefore one might consider making the capture of such event optional, so the web browser\index{web browser} is not strained unless explicitly asked by the developer of the application. This could be implemented with a simple function that sets a simple logical variable in the \texttt{x} object that is used in JavaScript to check whether to implement the callback function.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{#' @export}
\NormalTok{gio_capture_events <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(g) \{}
\NormalTok{  g}\OperatorTok{$}\NormalTok{x}\OperatorTok{$}\NormalTok{capture_events <-}\StringTok{ }\OtherTok{TRUE}
  \KeywordTok{return}\NormalTok{(g)}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

Then this could be used in JavaScript with an if statement.

\begin{Shaded}
\begin{Highlighting}[]
\ControlFlowTok{if}\NormalTok{(}\VariableTok{x}\NormalTok{.}\AttributeTok{capture_events}\NormalTok{)}
  \VariableTok{controller}\NormalTok{.}\AttributeTok{onCountryPicked}\NormalTok{(callback)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

One might also consider not sending back all the data. For instance, gio returns the coordinates of the selected country wherefrom arcs connect; this might be considered unnecessary. The code below only sets the input to the ISO code of the country selected.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{function} \AttributeTok{callback}\NormalTok{ (selectedCountry}\OperatorTok{,}\NormalTok{ relatedCountries) }\OperatorTok{\{}
  \VariableTok{Shiny}\NormalTok{.}\AttributeTok{setInputValue}\NormalTok{(}
    \VariableTok{el}\NormalTok{.}\AttributeTok{id} \OperatorTok{+} \StringTok{'_selected'}\OperatorTok{,} 
    \VariableTok{selectedCountry}\NormalTok{.}\AttributeTok{ISOCode}
\NormalTok{  )}\OperatorTok{;}
\OperatorTok{\}}
\end{Highlighting}
\end{Shaded}

\hypertarget{shiny-widgets-handlers}{%
\section{Input Handlers for Widgets}\label{shiny-widgets-handlers}}

Input handlers were explored in an earlier chapter where it was used to transform the results of an image classification model from a list to a data.frame. We can apply something very similar to this input data; the ``related countries'' returned consist of edges and should be reshaped into a data.frame as well (that looks like \texttt{gio}'s input data).

Below we create a handler that is going to loop over the list (over each arc) and return a data frame.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# handler.R}
\NormalTok{related_countries_handler <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(x, session, inputname)\{}
\NormalTok{  purrr}\OperatorTok{::}\KeywordTok{map_dfr}\NormalTok{(x, as.data.frame)}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

Then the handler must be registered with Shiny since handlers can only be registered once an excellent place to put it this is in the \texttt{.onLoad} function of the package.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# zzz.R}
\NormalTok{related_countries_handler <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(x, session, inputname)\{}
\NormalTok{  purrr}\OperatorTok{::}\KeywordTok{map_dfr}\NormalTok{(x, as.data.frame)}
\NormalTok{\}}

\NormalTok{.onLoad <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(libname, pkgname) \{}
\NormalTok{  shiny}\OperatorTok{::}\KeywordTok{registerInputHandler}\NormalTok{(}
    \StringTok{"gio.related.countries"}\NormalTok{, }
\NormalTok{    related_countries_handler}
\NormalTok{  )}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

Finally, we can reinstall the package with \texttt{devtools::install} and create a Shiny application to observe the change. In Figure \ref{fig:gio-input-handler} we use a large example dataset and, since the input now returns a data frame, we can display the input value in a table.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(DT)}
\KeywordTok{library}\NormalTok{(gio)}
\KeywordTok{library}\NormalTok{(shiny)}

\CommentTok{# large sample data}
\NormalTok{url <-}\StringTok{ }\KeywordTok{paste0}\NormalTok{(}
  \StringTok{"https://raw.githubusercontent.com/JohnCoene/"}\NormalTok{,}
  \StringTok{"javascript-for-r/master/data/countries.json"}
\NormalTok{)}
\NormalTok{arcs <-}\StringTok{ }\NormalTok{jsonlite}\OperatorTok{::}\KeywordTok{fromJSON}\NormalTok{(url)}

\NormalTok{ui <-}\StringTok{ }\KeywordTok{fluidPage}\NormalTok{(}
  \KeywordTok{gioOutput}\NormalTok{(}\StringTok{"globe"}\NormalTok{),}
  \KeywordTok{DTOutput}\NormalTok{(}\StringTok{"relatedCountries"}\NormalTok{)}
\NormalTok{)}

\NormalTok{server <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(input, output)\{}

\NormalTok{  output}\OperatorTok{$}\NormalTok{globe <-}\StringTok{ }\KeywordTok{renderGio}\NormalTok{(\{}
    \KeywordTok{gio}\NormalTok{(arcs, i, e, v)}
\NormalTok{  \})}

\NormalTok{  output}\OperatorTok{$}\NormalTok{relatedCountries <-}\StringTok{ }\KeywordTok{renderDT}\NormalTok{(\{}
    \KeywordTok{datatable}\NormalTok{(input}\OperatorTok{$}\NormalTok{globe_related)}
\NormalTok{  \})}

\NormalTok{\}}

\KeywordTok{shinyApp}\NormalTok{(ui, server)}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/gio-input-handler} 

}

\caption{Gio input data transformed to a data frame}\label{fig:gio-input-handler}
\end{figure}

\hypertarget{shiny-widgets-r-to-widgets}{%
\section{R to Widgets}\label{shiny-widgets-r-to-widgets}}

This book previously explored how to send data from the Shiny server to the front end; this section applies this to htmlwidgets. Currently, using gio in Shiny consists of generating the globe with the \texttt{renderGio} and complimentary \texttt{gioOutput} functions. This generates the complete visualisation, it creates the HTML\index{HTML} element where it places the globe, draws the arcs based on the data, sets the style, etc.

Now imagine that only one of those aspects needs changing, say the data, or the style, given the functions currently at hand one would have to redraw the entire visualisation, only this time changing the data or the style. This is inelegant and not efficient, most JavaScript visualisation libraries, including gio.js, will enable changing only certain aspects of the output without having to redraw it all from scratch.

Before we look into the implementation, let us create a Shiny application which would benefit from such a feature. The Shiny application below (Figure \ref{fig:gio-shiny-error}) provides a drop-down menu to select between two datasets to draw on the globe, running it reveals an issue with gio though. Upon selecting a dataset with the drop down a second globe appears underneath the original one. This is because internally gio.js creates a new element (\texttt{\textless{}canvas\textgreater{}}) within the \texttt{\textless{}div\textgreater{}} created by \texttt{htmlwidgets} when running \texttt{init} regardless of whether one was already created. Therefore, every call to \texttt{init} creates a new \texttt{\textless{}canvas\textgreater{}} with a different globe. Note that most visualisation libraries \emph{will not have that issue}, they will detect the existing output and override it instead.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(gio)}
\KeywordTok{library}\NormalTok{(shiny)}

\NormalTok{arcs1 <-}\StringTok{ }\KeywordTok{data.frame}\NormalTok{(}
  \DataTypeTok{e =} \KeywordTok{c}\NormalTok{(}\StringTok{"US"}\NormalTok{, }\StringTok{"CN"}\NormalTok{, }\StringTok{"RU"}\NormalTok{),}
  \DataTypeTok{i =} \KeywordTok{c}\NormalTok{(}\StringTok{"CN"}\NormalTok{, }\StringTok{"RU"}\NormalTok{, }\StringTok{"US"}\NormalTok{),}
  \DataTypeTok{v =} \KeywordTok{c}\NormalTok{(}\DecValTok{100}\NormalTok{, }\DecValTok{120}\NormalTok{, }\DecValTok{130}\NormalTok{)}
\NormalTok{)}

\NormalTok{arcs2 <-}\StringTok{ }\KeywordTok{data.frame}\NormalTok{(}
  \DataTypeTok{e =} \KeywordTok{c}\NormalTok{(}\StringTok{"CN"}\NormalTok{, }\StringTok{"CN"}\NormalTok{, }\StringTok{"JP"}\NormalTok{),}
  \DataTypeTok{i =} \KeywordTok{c}\NormalTok{(}\StringTok{"IN"}\NormalTok{, }\StringTok{"JP"}\NormalTok{, }\StringTok{"US"}\NormalTok{),}
  \DataTypeTok{v =} \KeywordTok{c}\NormalTok{(}\DecValTok{100}\NormalTok{, }\DecValTok{120}\NormalTok{, }\DecValTok{130}\NormalTok{)}
\NormalTok{)}

\NormalTok{ui <-}\StringTok{ }\KeywordTok{fluidPage}\NormalTok{(}
  \KeywordTok{selectInput}\NormalTok{(}
    \StringTok{"dataset"}\NormalTok{, }
    \StringTok{"Select a dataset"}\NormalTok{, }
    \DataTypeTok{choices =} \KeywordTok{c}\NormalTok{(}\StringTok{"First"}\NormalTok{, }\StringTok{"Second"}\NormalTok{)}
\NormalTok{  ),}
  \KeywordTok{gioOutput}\NormalTok{(}\StringTok{"globe"}\NormalTok{)}
\NormalTok{)}

\NormalTok{server <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(input, output)\{}

\NormalTok{  reactive_arcs <-}\StringTok{ }\KeywordTok{reactive}\NormalTok{(\{}
    \ControlFlowTok{if}\NormalTok{(input}\OperatorTok{$}\NormalTok{dataset }\OperatorTok{==}\StringTok{ "First"}\NormalTok{) }
      \KeywordTok{return}\NormalTok{(arcs1)}
    \KeywordTok{return}\NormalTok{(arcs2)}
\NormalTok{  \})}

\NormalTok{  output}\OperatorTok{$}\NormalTok{globe <-}\StringTok{ }\KeywordTok{renderGio}\NormalTok{(\{}
    \KeywordTok{gio}\NormalTok{(}\KeywordTok{reactive_arcs}\NormalTok{(), i, e, v)}
\NormalTok{  \})}

\NormalTok{\}}

\KeywordTok{shinyApp}\NormalTok{(ui, server)}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/gio-shiny-error} 

}

\caption{Gio issue in shiny}\label{fig:gio-shiny-error}
\end{figure}

A solution to this is to ensure the container (\texttt{el}) is empty before generating the visualisation. Incidentally, this can be executed with a JavaScript method previously used in this book: \texttt{innerHTML}.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{// gio.js}
\VariableTok{el}\NormalTok{.}\AttributeTok{innerHTML} \OperatorTok{=} \StringTok{''}\OperatorTok{;} \CommentTok{// empty el}
\NormalTok{controller }\OperatorTok{=} \KeywordTok{new} \VariableTok{GIO}\NormalTok{.}\AttributeTok{Controller}\NormalTok{(el)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

Now, using the dropdown to switch between dataset does not generate a new visualisation.

We got sidetracked, but this had to be fixed. Ideally, when the user selects a dataset from the dropdown the entire visualisation\index{visualisation} is not redrawn, only the underlying data (the arcs) changes. To do so, a new set of functions divorced from the ones currently at hand needs to be created. This separation will allow leaving the already created functions as-is, using \texttt{gio} and its corresponding \texttt{renderValue} JavaScript function to initialise a visualisation, and have a separate family of functions dedicated to working with different JavaScript functions which circumvent \texttt{renderValue} and directly change aspects of the visualisation, such as the underlying dataset.

This involves a few moving parts, thankfully some of them were already explored, just not in the context of htmlwidgets. The scheme is to send data from R to JavaScript using the formerly exploited \texttt{session\$sendCustomMessage}, then in JavaScript fetch the instance of the visualisation (\texttt{controller} in the case of gio) to interact with it (\texttt{e.g.\ controller.addData(data);}).

\hypertarget{shiny-widgets-send-data}{%
\subsection{Send Data from Widgets}\label{shiny-widgets-send-data}}

Let us start by creating the R function used to send data to JavaScript. This is hopefully reminiscent of a previous chapter; this function sends a message to JavaScript where it is paired with ``message handler'' that does something with said message. Note that for consistency the function uses the same arguments as the other function of the package which accepts data: \texttt{gio}.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{#' @export}
\NormalTok{gio_send_data <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(id, data, source, target, value, }
  \DataTypeTok{session =}\NormalTok{ shiny}\OperatorTok{::}\KeywordTok{getDefaultReactiveDomain}\NormalTok{())\{}

\NormalTok{  data <-}\StringTok{ }\NormalTok{dplyr}\OperatorTok{::}\KeywordTok{select}\NormalTok{(}
\NormalTok{    data,}
    \DataTypeTok{i =}\NormalTok{ \{\{ source \}\},}
    \DataTypeTok{e =}\NormalTok{ \{\{ target \}\},}
    \DataTypeTok{v =}\NormalTok{ \{\{ value \}\}}
\NormalTok{  )}
\NormalTok{  message <-}\StringTok{ }\KeywordTok{list}\NormalTok{(}\DataTypeTok{id =}\NormalTok{ id, }\DataTypeTok{data =}\NormalTok{ data)}
\NormalTok{  session}\OperatorTok{$}\KeywordTok{sendCustomMessage}\NormalTok{(}\StringTok{"send-data"}\NormalTok{, message)}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

The function takes the id of the visualisation the data is destined for, the data object itself, and a Shiny session used to send the data. The id of the visualisation is sent as part of the message and will be used to retrieve the instance of the visualisation and subsequently apply the new dataset. Note that we give this message the \texttt{send-data} identifier, this will be needed when we write its handler.

There is one caveat that will make it such that the above will not work. To have gio.js work with data changes had to be made to the serialiser\index{serialise} (using the \texttt{TOJSON\_ARGS} attribute), this cannot be used here. The data being sent with Shiny via the session object the problem reoccurs: Shiny, like htmlwidgets, serialises data frames column-wise and not row-wise. One can preview the way Shiny serialises\index{serialise} with \texttt{shiny:::toJSON} (three-colon).

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# preview shiny serialisation}
\NormalTok{shiny}\OperatorTok{:::}\KeywordTok{toJSON}\NormalTok{(arcs)}
\CommentTok{#> \{"e":["CN","CN"],"i":["US","RU"],"v":[3300000,10000]\}}
\end{Highlighting}
\end{Shaded}

Unfortunately this serialiser cannot be changed, therefore we have to reformat the data to a list which resembles the JSON\index{JSON} output desired, using \texttt{apply} to turn every row into a list will do the job in most cases.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{#' @export}
\NormalTok{gio_send_data <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(id, data, source, target, value, }
  \DataTypeTok{session =}\NormalTok{ shiny}\OperatorTok{::}\KeywordTok{getDefaultReactiveDomain}\NormalTok{())\{}

\NormalTok{  data <-}\StringTok{ }\NormalTok{dplyr}\OperatorTok{::}\KeywordTok{select}\NormalTok{(}
\NormalTok{    data,}
    \DataTypeTok{i =}\NormalTok{ \{\{ source \}\},}
    \DataTypeTok{e =}\NormalTok{ \{\{ target \}\},}
    \DataTypeTok{v =}\NormalTok{ \{\{ value \}\}}
\NormalTok{  )}
\NormalTok{  message <-}\StringTok{ }\KeywordTok{list}\NormalTok{(}\DataTypeTok{id =}\NormalTok{ id, }\DataTypeTok{data =} \KeywordTok{apply}\NormalTok{(data, }\DecValTok{1}\NormalTok{, as.list))}
\NormalTok{  session}\OperatorTok{$}\KeywordTok{sendCustomMessage}\NormalTok{(}\StringTok{"send-data"}\NormalTok{, message)}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

\hypertarget{shiny-widgets-retrieve}{%
\subsection{Retrieve Widget Instance}\label{shiny-widgets-retrieve}}

We will need to be able to access the instance of the visualisation (\texttt{controller}) outside of the function \texttt{factory}. This can be made accessible by adding a function (technically a method) that returns the \texttt{controller}. Below we create a function called \texttt{getGlobe} which returns the \texttt{controller}.

\begin{Shaded}
\begin{Highlighting}[]
\VariableTok{HTMLWidgets}\NormalTok{.}\AttributeTok{widget}\NormalTok{(}\OperatorTok{\{}

  \DataTypeTok{name}\OperatorTok{:} \StringTok{'gio'}\OperatorTok{,}

  \DataTypeTok{type}\OperatorTok{:} \StringTok{'output'}\OperatorTok{,}

  \DataTypeTok{factory}\OperatorTok{:} \KeywordTok{function}\NormalTok{(el}\OperatorTok{,}\NormalTok{ width}\OperatorTok{,}\NormalTok{ height) }\OperatorTok{\{}

    \CommentTok{// }\AlertTok{TODO}\CommentTok{: define shared variables for this instance}
    \KeywordTok{var}\NormalTok{ controller}\OperatorTok{;}

    \CommentTok{// selection handle}
    \KeywordTok{var}\NormalTok{ sel_handle }\OperatorTok{=} \KeywordTok{new} \VariableTok{crosstalk}\NormalTok{.}\AttributeTok{SelectionHandle}\NormalTok{()}\OperatorTok{;}

    \VariableTok{sel_handle}\NormalTok{.}\AttributeTok{on}\NormalTok{(}\StringTok{"change"}\OperatorTok{,} \KeywordTok{function}\NormalTok{(e) }\OperatorTok{\{}
      \ControlFlowTok{if}\NormalTok{ (}\VariableTok{e}\NormalTok{.}\AttributeTok{sender} \OperatorTok{!==}\NormalTok{ sel_handle) }\OperatorTok{\{}
        \CommentTok{// clear selection}
      \OperatorTok{\}}
      \VariableTok{controller}\NormalTok{.}\AttributeTok{switchCountry}\NormalTok{(}\VariableTok{e}\NormalTok{.}\AttributeTok{value}\NormalTok{[}\DecValTok{0}\NormalTok{])}\OperatorTok{;}
    \OperatorTok{\}}\NormalTok{)}\OperatorTok{;}


    \ControlFlowTok{return} \OperatorTok{\{}

      \DataTypeTok{renderValue}\OperatorTok{:} \KeywordTok{function}\NormalTok{(x) }\OperatorTok{\{}

        \VariableTok{el}\NormalTok{.}\AttributeTok{innerHTML} \OperatorTok{=} \StringTok{''}\OperatorTok{;}
\NormalTok{        controller }\OperatorTok{=} \KeywordTok{new} \VariableTok{GIO}\NormalTok{.}\AttributeTok{Controller}\NormalTok{(el}\OperatorTok{,} \VariableTok{x}\NormalTok{.}\AttributeTok{configs}\NormalTok{)}\OperatorTok{;}

        \CommentTok{// group}
        \VariableTok{sel_handle}\NormalTok{.}\AttributeTok{setGroup}\NormalTok{(}\VariableTok{x}\NormalTok{.}\VariableTok{crosstalk}\NormalTok{.}\AttributeTok{group}\NormalTok{)}\OperatorTok{;}
        
        \CommentTok{// add data}
        \VariableTok{controller}\NormalTok{.}\AttributeTok{addData}\NormalTok{(}\VariableTok{x}\NormalTok{.}\AttributeTok{data}\NormalTok{)}\OperatorTok{;}

        \VariableTok{controller}\NormalTok{.}\AttributeTok{setStyle}\NormalTok{(}\VariableTok{x}\NormalTok{.}\AttributeTok{style}\NormalTok{)}\OperatorTok{;}

        \CommentTok{// callback}
        \VariableTok{controller}\NormalTok{.}\AttributeTok{onCountryPicked}\NormalTok{(callback)}\OperatorTok{;}

        \KeywordTok{function} \AttributeTok{callback}\NormalTok{ (selectedCountry}\OperatorTok{,}\NormalTok{ relatedCountries) }\OperatorTok{\{}
          \VariableTok{sel_handle}\NormalTok{.}\AttributeTok{set}\NormalTok{([}\VariableTok{selectedCountry}\NormalTok{.}\AttributeTok{ISOCode}\NormalTok{])}\OperatorTok{;}
          \VariableTok{Shiny}\NormalTok{.}\AttributeTok{setInputValue}\NormalTok{(}
            \VariableTok{el}\NormalTok{.}\AttributeTok{id} \OperatorTok{+} \StringTok{'_selected'}\OperatorTok{,} 
\NormalTok{            selectedCountry}
\NormalTok{          )}\OperatorTok{;}
          \VariableTok{Shiny}\NormalTok{.}\AttributeTok{setInputValue}\NormalTok{(}
            \VariableTok{el}\NormalTok{.}\AttributeTok{id} \OperatorTok{+} \StringTok{'_related:gio.related.countries'}\OperatorTok{,} 
\NormalTok{            relatedCountries}
\NormalTok{          )}\OperatorTok{;}
        \OperatorTok{\}}

        \CommentTok{// use stats}
        \ControlFlowTok{if}\NormalTok{(}\VariableTok{x}\NormalTok{.}\AttributeTok{stats}\NormalTok{)}
          \VariableTok{controller}\NormalTok{.}\AttributeTok{enableStats}\NormalTok{()}\OperatorTok{;}

        \CommentTok{// render}
        \VariableTok{controller}\NormalTok{.}\AttributeTok{init}\NormalTok{()}\OperatorTok{;}

      \OperatorTok{\},}

      \DataTypeTok{resize}\OperatorTok{:} \KeywordTok{function}\NormalTok{(width}\OperatorTok{,}\NormalTok{ height) }\OperatorTok{\{}

        \CommentTok{// }\AlertTok{TODO}\CommentTok{: code to re-render the widget with a new size}
        \VariableTok{controller}\NormalTok{.}\AttributeTok{resizeUpdate}\NormalTok{()}

      \OperatorTok{\},}

      \DataTypeTok{getGlobe}\OperatorTok{:} \KeywordTok{function}\NormalTok{()}\OperatorTok{\{}
        \ControlFlowTok{return}\NormalTok{ controller}\OperatorTok{;}
      \OperatorTok{\}}

    \OperatorTok{\};}
  \OperatorTok{\}}
\OperatorTok{\}}\NormalTok{)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

Then, anywhere in the \texttt{gio.js} file, we create a function that uses \texttt{HTMLWidgets.find} to retrieve the instance of the htmlwidgets it takes a selector as input. We concatenate the pound sign to select the widget based on its id (\texttt{\#id}, \texttt{.class}). This, in effect, returns an object, which includes all the functions returned by the \texttt{factory} function: \texttt{renderValue}, \texttt{resize}, and \texttt{getGlobe}. We can therefore use the \texttt{getGlobe} method available from that object to retrieve the actual \texttt{controller}.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{// gio.js}
\KeywordTok{function} \AttributeTok{get_gio}\NormalTok{(id)}\OperatorTok{\{}
  \KeywordTok{var}\NormalTok{ widget }\OperatorTok{=} \VariableTok{HTMLWidgets}\NormalTok{.}\AttributeTok{find}\NormalTok{(}\StringTok{"#"} \OperatorTok{+}\NormalTok{ id)}\OperatorTok{;}
  \KeywordTok{var}\NormalTok{ globe }\OperatorTok{=} \VariableTok{widget}\NormalTok{.}\AttributeTok{getGlobe}\NormalTok{()}\OperatorTok{;}
  \ControlFlowTok{return}\NormalTok{ globe}\OperatorTok{;}
\OperatorTok{\}}
\end{Highlighting}
\end{Shaded}

\hypertarget{shiny-widgets-handle-data}{%
\subsection{Handle Data}\label{shiny-widgets-handle-data}}

We can now turn our attention to actually applying the data sent from the R server to the visualisation: the ``message handler.'' Registering the message handler is only relevant if Shiny is running. Therefore htmlwidgets comes with a function to check whether that is the case, which is useful to avoid needless errors. We can thus use it in an if-statement in which all message handlers will be registered.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{// gio.js}

\CommentTok{// check if shiny running}
\ControlFlowTok{if}\NormalTok{ (}\VariableTok{HTMLWidgets}\NormalTok{.}\AttributeTok{shinyMode}\NormalTok{)}\OperatorTok{\{}

  \CommentTok{// send-data message handler}
  \VariableTok{Shiny}\NormalTok{.}\AttributeTok{addCustomMessageHandler}\NormalTok{(}
\NormalTok{    type }\OperatorTok{=} \StringTok{'send-data'}\OperatorTok{,} \KeywordTok{function}\NormalTok{(message) }\OperatorTok{\{}

  \OperatorTok{\}}\NormalTok{)}\OperatorTok{;}

\OperatorTok{\}}
\end{Highlighting}
\end{Shaded}

What the currently empty \texttt{send-data} message handler should do is fetch the widget using the \texttt{id} sent from R with the \texttt{get\_gio} function and then use the \texttt{addData} method to override the previously-defined arcs.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{// gio.js}

\CommentTok{// check if shiny running}
\ControlFlowTok{if}\NormalTok{ (}\VariableTok{HTMLWidgets}\NormalTok{.}\AttributeTok{shinyMode}\NormalTok{)}\OperatorTok{\{}

  \CommentTok{// send-data message handler}
  \VariableTok{Shiny}\NormalTok{.}\AttributeTok{addCustomMessageHandler}\NormalTok{(}
\NormalTok{    type }\OperatorTok{=} \StringTok{'send-data'}\OperatorTok{,} \KeywordTok{function}\NormalTok{(message) }\OperatorTok{\{}

    \CommentTok{// retrieve controller}
    \KeywordTok{var}\NormalTok{ controller }\OperatorTok{=} \AttributeTok{get_gio}\NormalTok{(}\VariableTok{message}\NormalTok{.}\AttributeTok{id}\NormalTok{)}\OperatorTok{;}

    \CommentTok{// add data}
    \VariableTok{controller}\NormalTok{.}\AttributeTok{addData}\NormalTok{(}\VariableTok{message}\NormalTok{.}\AttributeTok{data}\NormalTok{)}\OperatorTok{;}

  \OperatorTok{\}}\NormalTok{)}\OperatorTok{;}

\OperatorTok{\}}
\end{Highlighting}
\end{Shaded}

We can then build a Shiny application to test the new functionality.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(gio)}
\KeywordTok{library}\NormalTok{(shiny)}

\CommentTok{# two phoney datasets}
\NormalTok{arcs1 <-}\StringTok{ }\KeywordTok{data.frame}\NormalTok{(}
  \DataTypeTok{e =} \KeywordTok{c}\NormalTok{(}\StringTok{"US"}\NormalTok{, }\StringTok{"CN"}\NormalTok{, }\StringTok{"RU"}\NormalTok{),}
  \DataTypeTok{i =} \KeywordTok{c}\NormalTok{(}\StringTok{"CN"}\NormalTok{, }\StringTok{"RU"}\NormalTok{, }\StringTok{"US"}\NormalTok{),}
  \DataTypeTok{v =} \KeywordTok{c}\NormalTok{(}\DecValTok{100}\NormalTok{, }\DecValTok{120}\NormalTok{, }\DecValTok{130}\NormalTok{)}
\NormalTok{)}

\NormalTok{arcs2 <-}\StringTok{ }\KeywordTok{data.frame}\NormalTok{(}
  \DataTypeTok{e =} \KeywordTok{c}\NormalTok{(}\StringTok{"CN"}\NormalTok{, }\StringTok{"CN"}\NormalTok{, }\StringTok{"JP"}\NormalTok{),}
  \DataTypeTok{i =} \KeywordTok{c}\NormalTok{(}\StringTok{"IN"}\NormalTok{, }\StringTok{"JP"}\NormalTok{, }\StringTok{"US"}\NormalTok{),}
  \DataTypeTok{v =} \KeywordTok{c}\NormalTok{(}\DecValTok{100}\NormalTok{, }\DecValTok{120}\NormalTok{, }\DecValTok{130}\NormalTok{)}
\NormalTok{)}

\NormalTok{ui <-}\StringTok{ }\KeywordTok{fluidPage}\NormalTok{(}
  \KeywordTok{selectInput}\NormalTok{(}
    \StringTok{"dataset"}\NormalTok{, }
    \StringTok{"Select a dataset"}\NormalTok{, }
    \DataTypeTok{choices =} \KeywordTok{c}\NormalTok{(}\StringTok{"First"}\NormalTok{, }\StringTok{"Second"}\NormalTok{)}
\NormalTok{  ),}
  \KeywordTok{gioOutput}\NormalTok{(}\StringTok{"globe"}\NormalTok{)}
\NormalTok{)}

\NormalTok{server <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(input, output)\{}

\NormalTok{  reactive_arcs <-}\StringTok{ }\KeywordTok{reactive}\NormalTok{(\{}
    \ControlFlowTok{if}\NormalTok{(input}\OperatorTok{$}\NormalTok{dataset }\OperatorTok{==}\StringTok{ "First"}\NormalTok{) }
      \KeywordTok{return}\NormalTok{(arcs1)}
    \KeywordTok{return}\NormalTok{(arcs2)}
\NormalTok{  \})}

\NormalTok{  output}\OperatorTok{$}\NormalTok{globe <-}\StringTok{ }\KeywordTok{renderGio}\NormalTok{(\{}
    \KeywordTok{gio}\NormalTok{(arcs1, i, e, v)}
\NormalTok{  \})}

  \KeywordTok{observeEvent}\NormalTok{(input}\OperatorTok{$}\NormalTok{dataset, \{}
    \ControlFlowTok{if}\NormalTok{(input}\OperatorTok{$}\NormalTok{dataset }\OperatorTok{==}\StringTok{ "First"}\NormalTok{)}
\NormalTok{      data <-}\StringTok{ }\NormalTok{arcs1}
    \ControlFlowTok{else}
\NormalTok{      data <-}\StringTok{ }\NormalTok{arcs2}
    
    \KeywordTok{gio_send_data}\NormalTok{(}\StringTok{"globe"}\NormalTok{, data, i, e, v)}
\NormalTok{  \})}

\NormalTok{\}}

\KeywordTok{shinyApp}\NormalTok{(ui, server)}
\end{Highlighting}
\end{Shaded}

Switching dataset with the dropdown only changes the data; it makes for a much smoother animation, even the difference in the speed at which the effect is visible on the visualisation is perceivable.

\hypertarget{shiny-widgets-proxy}{%
\section{Proxy Function}\label{shiny-widgets-proxy}}

Before we add other similar functions, we ought to pause and consider the API this provides the user. There are two points, every function such as \texttt{gio\_send\_data}, will need to accept the \texttt{id} and \texttt{session} arguments. It will be tedious to so every time, following the old ``don't repeat yourself'' adage we ought to abstract this further.

This can be remedied to by introducing what is often referred to as a ``proxy.'' A proxy is just a representation of the graph, or pragmatically, an object that contains the id of the visualisation\index{visualisation} and a Shiny session. This object can subsequently be piped\index{pipe} to other functions, thereby providing not only a cleaner but also a more consistent API.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{#' @export}
\NormalTok{gio_proxy <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(id, }
  \DataTypeTok{session =}\NormalTok{ shiny}\OperatorTok{::}\KeywordTok{getDefaultReactiveDomain}\NormalTok{()}
\NormalTok{)\{}

  \KeywordTok{list}\NormalTok{(}\DataTypeTok{id =}\NormalTok{ id, }\DataTypeTok{session =}\NormalTok{ session)}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

Above we create a function called \texttt{gio\_proxy}; it takes the \texttt{id} of the chart one wants to build a proxy for, as well as the Shiny \texttt{session}, these are returned in the form of a list. Next, we should adapt the \texttt{gio\_send\_data} so that it accepts the output of \texttt{gioProxy} instead of the \texttt{id} and \texttt{session} as done previously. In order to allow chaining such functions, we also make sure it returns the \texttt{proxy} object.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{#' @export}
\NormalTok{gio_send_data <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(proxy, data)\{}
\NormalTok{  message <-}\StringTok{ }\KeywordTok{list}\NormalTok{(}\DataTypeTok{id =}\NormalTok{ proxy}\OperatorTok{$}\NormalTok{id, }\DataTypeTok{data =} \KeywordTok{apply}\NormalTok{(data, }\DecValTok{1}\NormalTok{, as.list))}
\NormalTok{  proxy}\OperatorTok{$}\NormalTok{session}\OperatorTok{$}\KeywordTok{sendCustomMessage}\NormalTok{(}\StringTok{"send-data"}\NormalTok{, message)}
  \KeywordTok{return}\NormalTok{(proxy)}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

\hypertarget{shiny-widgets-clear-data}{%
\section{Clear Data}\label{shiny-widgets-clear-data}}

In order to actively demonstrate the advantage of the ``proxy'' function as well as to hammer home how such functions work, we shall build another, which removes all data from the globe. In JavaScript, it's as simple as \texttt{controller.clearData();}.

The journey starts with the R code, where we create a new function that sends a message to clear the data; the message only needs to contain the id of the visualisation from which data needs to be cleared, as before it will be used to retrieve the \texttt{controller} from which the \texttt{clearData} method is available.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{#' @export}
\NormalTok{gio_clear_data <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(proxy)\{}
\NormalTok{  message <-}\StringTok{ }\KeywordTok{list}\NormalTok{(}\DataTypeTok{id =}\NormalTok{ proxy}\OperatorTok{$}\NormalTok{id)}
\NormalTok{  proxy}\OperatorTok{$}\NormalTok{session}\OperatorTok{$}\KeywordTok{sendCustomMessage}\NormalTok{(}\StringTok{"clear-data"}\NormalTok{, message)}
  \KeywordTok{return}\NormalTok{(proxy)}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

Now onto the JavaScript code to catch that message and actually clear the data from the globe. That function is very similar to what was previously shown, the only difference is the name of the message handler and the method used on the controller.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{// gio.js}
\VariableTok{Shiny}\NormalTok{.}\AttributeTok{addCustomMessageHandler}\NormalTok{(}
\NormalTok{  type }\OperatorTok{=} \StringTok{'clear-data'}\OperatorTok{,} \KeywordTok{function}\NormalTok{(message) }\OperatorTok{\{}

    \KeywordTok{var}\NormalTok{ controller }\OperatorTok{=} \AttributeTok{get_gio}\NormalTok{(}\VariableTok{message}\NormalTok{.}\AttributeTok{id}\NormalTok{)}\OperatorTok{;}
    \VariableTok{controller}\NormalTok{.}\AttributeTok{clearData}\NormalTok{()}\OperatorTok{;}
\OperatorTok{\}}\NormalTok{)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

Then one can build an application to test that new function. We build a Shiny application with a button to add the data to the visualisation and another to clear data from it, as shown in Figure \ref{fig:giod-shiny-clear-data}.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(gio)}
\KeywordTok{library}\NormalTok{(shiny)}

\CommentTok{# phoney dataset}
\NormalTok{arcs <-}\StringTok{ }\KeywordTok{data.frame}\NormalTok{(}
  \DataTypeTok{e =} \KeywordTok{c}\NormalTok{(}\StringTok{"US"}\NormalTok{, }\StringTok{"CN"}\NormalTok{, }\StringTok{"RU"}\NormalTok{),}
  \DataTypeTok{i =} \KeywordTok{c}\NormalTok{(}\StringTok{"CN"}\NormalTok{, }\StringTok{"RU"}\NormalTok{, }\StringTok{"US"}\NormalTok{),}
  \DataTypeTok{v =} \KeywordTok{c}\NormalTok{(}\DecValTok{100}\NormalTok{, }\DecValTok{120}\NormalTok{, }\DecValTok{130}\NormalTok{)}
\NormalTok{)}

\NormalTok{ui <-}\StringTok{ }\KeywordTok{fluidPage}\NormalTok{(}
  \KeywordTok{actionButton}\NormalTok{(}\StringTok{"load"}\NormalTok{, }\StringTok{"Load data"}\NormalTok{),}
  \KeywordTok{actionButton}\NormalTok{(}\StringTok{"clear"}\NormalTok{, }\StringTok{"Clear data"}\NormalTok{),}
  \KeywordTok{gioOutput}\NormalTok{(}\StringTok{"globe"}\NormalTok{)}
\NormalTok{)}

\NormalTok{server <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(input, output)\{}

\NormalTok{  output}\OperatorTok{$}\NormalTok{globe <-}\StringTok{ }\KeywordTok{renderGio}\NormalTok{(\{}
    \KeywordTok{gio}\NormalTok{(arcs, i, e, v)}
\NormalTok{  \})}

  \KeywordTok{observeEvent}\NormalTok{(input}\OperatorTok{$}\NormalTok{load, \{}
    \KeywordTok{gio_proxy}\NormalTok{(}\StringTok{"globe"}\NormalTok{) }\OperatorTok{%>%}\StringTok{ }
\StringTok{      }\KeywordTok{gio_send_data}\NormalTok{(arcs, i, e, v)}
\NormalTok{  \})}

  \KeywordTok{observeEvent}\NormalTok{(input}\OperatorTok{$}\NormalTok{clear, \{}
    \KeywordTok{gio_proxy}\NormalTok{(}\StringTok{"globe"}\NormalTok{) }\OperatorTok{%>%}\StringTok{ }
\StringTok{      }\KeywordTok{gio_clear_data}\NormalTok{()}
\NormalTok{  \})}

\NormalTok{\}}

\KeywordTok{shinyApp}\NormalTok{(ui, server)}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/gio-shiny-clear} 

}

\caption{Gio with clear data proxy}\label{fig:giod-shiny-clear-data}
\end{figure}

\hypertarget{shiny-widgets-update}{%
\section{Update the Widget}\label{shiny-widgets-update}}

The previous proxies defined worked for reasons unbeknownst to the author of this book. It will not work with all methods. The reason it will not work is one that is likely to occur with many other visualisation libraries. For instance, one can attempt to develop a function to dynamically change the style without having to redraw the entire globe, starting again with the R function.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{#' @export}
\NormalTok{gio_set_style <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(proxy, style)\{}
\NormalTok{  message <-}\StringTok{ }\KeywordTok{list}\NormalTok{(}\DataTypeTok{id =}\NormalTok{ proxy}\OperatorTok{$}\NormalTok{id, }\DataTypeTok{style =}\NormalTok{ style)}
\NormalTok{  proxy}\OperatorTok{$}\NormalTok{session}\OperatorTok{$}\KeywordTok{sendCustomMessage}\NormalTok{(}\StringTok{"set-style"}\NormalTok{, message)}
  \KeywordTok{return}\NormalTok{(proxy)}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

Then, adding the JavaScript handler.

\begin{Shaded}
\begin{Highlighting}[]
\VariableTok{Shiny}\NormalTok{.}\AttributeTok{addCustomMessageHandler}\NormalTok{(}
\NormalTok{  type }\OperatorTok{=} \StringTok{'set-style'}\OperatorTok{,} \KeywordTok{function}\NormalTok{(message) }\OperatorTok{\{}
    \KeywordTok{var}\NormalTok{ controller }\OperatorTok{=} \AttributeTok{get_gio}\NormalTok{(}\VariableTok{message}\NormalTok{.}\AttributeTok{id}\NormalTok{)}\OperatorTok{;}
    \VariableTok{controller}\NormalTok{.}\AttributeTok{setStyle}\NormalTok{(}\VariableTok{message}\NormalTok{.}\AttributeTok{style}\NormalTok{)}\OperatorTok{;}
\OperatorTok{\}}\NormalTok{)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

At this stage, one can try the function in a Shiny application, but it will not work because most such methods that change underlying aspects of a visualisation will not be reflected in real-time. Gio.js, and many other libraries, will require one to explicitly ask for an update so the changes take effect. This has multiple advantages, one can stack multiple visual changes to execute them at the same time, and one can manage the load on the front end.

\begin{Shaded}
\begin{Highlighting}[]
\VariableTok{Shiny}\NormalTok{.}\AttributeTok{addCustomMessageHandler}\NormalTok{(}
\NormalTok{  type }\OperatorTok{=} \StringTok{'set-style'}\OperatorTok{,} \KeywordTok{function}\NormalTok{(message) }\OperatorTok{\{}
    \KeywordTok{var}\NormalTok{ controller }\OperatorTok{=} \AttributeTok{get_gio}\NormalTok{(}\VariableTok{message}\NormalTok{.}\AttributeTok{id}\NormalTok{)}\OperatorTok{;}
    \VariableTok{controller}\NormalTok{.}\AttributeTok{setStyle}\NormalTok{(}\VariableTok{message}\NormalTok{.}\AttributeTok{style}\NormalTok{)}\OperatorTok{;}
    \VariableTok{controller}\NormalTok{.}\AttributeTok{update}\NormalTok{()}\OperatorTok{;} \CommentTok{// force update the visualisation}
\OperatorTok{\}}\NormalTok{)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

This forces the chart to update, applying the new style. Below we write an application that provides a dropdown to switch between two styles (Figure \ref{fig:gio-shiny-style}).

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(gio)}
\KeywordTok{library}\NormalTok{(shiny)}

\CommentTok{# two phoney datasets}
\NormalTok{arcs <-}\StringTok{ }\KeywordTok{data.frame}\NormalTok{(}
  \DataTypeTok{e =} \KeywordTok{c}\NormalTok{(}\StringTok{"US"}\NormalTok{, }\StringTok{"CN"}\NormalTok{, }\StringTok{"RU"}\NormalTok{),}
  \DataTypeTok{i =} \KeywordTok{c}\NormalTok{(}\StringTok{"CN"}\NormalTok{, }\StringTok{"RU"}\NormalTok{, }\StringTok{"US"}\NormalTok{),}
  \DataTypeTok{v =} \KeywordTok{c}\NormalTok{(}\DecValTok{100}\NormalTok{, }\DecValTok{120}\NormalTok{, }\DecValTok{130}\NormalTok{)}
\NormalTok{)}

\NormalTok{ui <-}\StringTok{ }\KeywordTok{fluidPage}\NormalTok{(}
  \KeywordTok{selectInput}\NormalTok{(}
    \StringTok{"style"}\NormalTok{, }
    \StringTok{"Select a style"}\NormalTok{, }
    \DataTypeTok{choices =} \KeywordTok{c}\NormalTok{(}\StringTok{"blueInk"}\NormalTok{, }\StringTok{"earlySpring"}\NormalTok{)}
\NormalTok{  ),}
  \KeywordTok{gioOutput}\NormalTok{(}\StringTok{"globe"}\NormalTok{)}
\NormalTok{)}

\NormalTok{server <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(input, output)\{}
\NormalTok{  output}\OperatorTok{$}\NormalTok{globe <-}\StringTok{ }\KeywordTok{renderGio}\NormalTok{(\{}
    \KeywordTok{gio}\NormalTok{(arcs1, i, e , v)}
\NormalTok{  \})}

  \KeywordTok{observeEvent}\NormalTok{(input}\OperatorTok{$}\NormalTok{style, \{}
    \KeywordTok{gio_proxy}\NormalTok{(}\StringTok{"globe"}\NormalTok{) }\OperatorTok{%>%}\StringTok{ }
\StringTok{      }\KeywordTok{gio_set_style}\NormalTok{(input}\OperatorTok{$}\NormalTok{style)}
\NormalTok{  \})}

\NormalTok{\}}
\KeywordTok{shinyApp}\NormalTok{(ui, server)}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/gio-shiny-style} 

}

\caption{Gio with dynamic style}\label{fig:gio-shiny-style}
\end{figure}

\hypertarget{part-javascript-for-computations}{%
\part{JavaScript for Computations}\label{part-javascript-for-computations}}

\hypertarget{v8}{%
\chapter{The V8 Engine}\label{v8}}

V8 is an R interface to Google's open-source JavaScript engine of the same name; it powers Google Chrome, Node.js, and many other things. It is the last integration of JavaScript with R that is covered in this book. Both the V8 package and the engine it wraps are straightforward yet amazingly powerful.

\hypertarget{v8-installation}{%
\section{Installation}\label{v8-installation}}

First, install the V8 engine itself, instructions to do so are well detailed on \href{https://github.com/jeroen/v8\#installation}{V8's README} and below.

On Debian or Ubuntu use the code below from the terminal to install \href{https://v8.dev/}{libv8}.

\begin{Shaded}
\begin{Highlighting}[]
\FunctionTok{sudo}\NormalTok{ apt-get install -y libv8-dev}
\end{Highlighting}
\end{Shaded}

On Centos install v8-devel, which requires the EPEL tools.

\begin{Shaded}
\begin{Highlighting}[]
\FunctionTok{sudo}\NormalTok{ yum install epel-release}
\FunctionTok{sudo}\NormalTok{ yum install v8-devel}
\end{Highlighting}
\end{Shaded}

On Mac OS use \href{https://brew.sh/}{Homebrew}.

\begin{Shaded}
\begin{Highlighting}[]
\ExtensionTok{brew}\NormalTok{ install v8}
\end{Highlighting}
\end{Shaded}

Then install the R package from \index{CRAN}.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{install.packages}\NormalTok{(}\StringTok{"V8"}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

\hypertarget{v8-basics}{%
\section{Basics}\label{v8-basics}}

V8 provides an JavaScript execution environment\index{environment} through returning a closure-based object with \texttt{v8()}; Each of such environments\index{environment} is independent of another.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(V8)}

\NormalTok{engine <-}\StringTok{ }\KeywordTok{v8}\NormalTok{()}
\end{Highlighting}
\end{Shaded}

The \texttt{eval} method allows running JavaScript code from R.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{engine}\OperatorTok{$}\KeywordTok{eval}\NormalTok{(}\StringTok{"var x = 3 + 4;"}\NormalTok{) }\CommentTok{# this is evaluated in R}
\NormalTok{engine}\OperatorTok{$}\KeywordTok{eval}\NormalTok{(}\StringTok{"x"}\NormalTok{)}
\CommentTok{#> [1] "7"}
\end{Highlighting}
\end{Shaded}

Two observations are worth making on the above snippet of code. First, the variable we got back in R is a character vector when it should have been either an integer or a numeric. This is because we used the \texttt{eval} method, which returns what is printed in the V8 console, but \texttt{get} is more appropriate; it converts the output to its appropriate R equivalent.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# retrieve the previously created variable}
\NormalTok{(x <-}\StringTok{ }\NormalTok{engine}\OperatorTok{$}\KeywordTok{get}\NormalTok{(}\StringTok{"x"}\NormalTok{))}
\CommentTok{#> [1] 7}
\KeywordTok{class}\NormalTok{(x)}
\CommentTok{#> [1] "integer"}
\end{Highlighting}
\end{Shaded}

Second, while creating a scalar with \texttt{eval("var\ x\ =\ 1;")} appears painless, imagine if you will the horror of having to convert a data frame to a JavaScript array via jsonlite then flatten it to character string so it can be used with the \texttt{eval} method. Horrid. Thankfully V8 comes with a method \texttt{assign}, complimentary to \texttt{get}, which declares R objects as JavaScript variables. It takes two arguments, first the name of the variable to create, second the object to assign to it.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# assign and retrieve a data.frame}
\NormalTok{engine}\OperatorTok{$}\KeywordTok{assign}\NormalTok{(}\StringTok{"vehicles"}\NormalTok{, cars[}\DecValTok{1}\OperatorTok{:}\DecValTok{3}\NormalTok{, ])}
\NormalTok{engine}\OperatorTok{$}\KeywordTok{get}\NormalTok{(}\StringTok{"vehicles"}\NormalTok{)}
\CommentTok{#>   speed dist}
\CommentTok{#> 1     4    2}
\CommentTok{#> 2     4   10}
\CommentTok{#> 3     7    4}
\end{Highlighting}
\end{Shaded}

All of the conversion is handled by V8 internally with jsonlite, as demonstrated in the previous chapter. We can confirm that the data frame was converted to a list row-wise, using \texttt{JSON.stringify} to display how the object is stored in V8.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{cat}\NormalTok{(engine}\OperatorTok{$}\KeywordTok{eval}\NormalTok{(}\StringTok{"JSON.stringify(vehicles, null, 2);"}\NormalTok{))}
\CommentTok{#> [}
\CommentTok{#>   \{}
\CommentTok{#>     "speed": 4,}
\CommentTok{#>     "dist": 2}
\CommentTok{#>   \},}
\CommentTok{#>   \{}
\CommentTok{#>     "speed": 4,}
\CommentTok{#>     "dist": 10}
\CommentTok{#>   \},}
\CommentTok{#>   \{}
\CommentTok{#>     "speed": 7,}
\CommentTok{#>     "dist": 4}
\CommentTok{#>   \}}
\CommentTok{#> ]}
\end{Highlighting}
\end{Shaded}

However this reveals a tedious cyclical loop: 1) creating an object in JavaScript to 2) run a function on the aforementioned object, 3) get the results back in R, and repeat. So V8 also allows calling JavaScript functions on R objects directly with the \texttt{call} method and obtains the results back in R.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{engine}\OperatorTok{$}\KeywordTok{eval}\NormalTok{(}\StringTok{"new Date();"}\NormalTok{) }\CommentTok{# using eval}
\end{Highlighting}
\end{Shaded}

\begin{verbatim}
#> [1] "Sun Oct 18 2020 18:34:45 GMT+0200 
  (Central European Summer Time)"
\end{verbatim}

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{engine}\OperatorTok{$}\KeywordTok{call}\NormalTok{(}\StringTok{"Date"}\NormalTok{, }\KeywordTok{Sys.Date}\NormalTok{()) }\CommentTok{# using call}
\end{Highlighting}
\end{Shaded}

\begin{verbatim}
#> [1] "Sun Oct 18 2020 18:34:45 GMT+0200 
  (Central European Summer Time)"
\end{verbatim}

Finally, one can run code interactively rather than as strings by calling the console from the engine with \texttt{engine\$console()}. You can then exit the console by typing \texttt{exit} or hitting the ESC key.

\hypertarget{v8-external}{%
\section{External Libraries}\label{v8-external}}

V8 is quite bare in and of itself; there is, for instance, no functionalities built in to read or write files from disk. It thus becomes truly interesting when you can leverage JavaScript libraries. We'll demonstrate this using \href{https://fusejs.io/}{fuse.js} a fuzzy-search library.

The very first step of integrating any external library is to look at the code (often examples) to grasp an idea of what is to be achieved from R. Below is an example from the official documentation. First, an array of two \texttt{books} is defined; this is later used to test the search. Then another array of options is defined. This should at the very least include the key(s) that should be searched; here it is set to search through the title and authors. Then, the fuse object is initialised based on the array of books and the options. Finally, the \texttt{search} method is used to retrieve all books, the title or author of which partially match the term \texttt{tion}.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{// books to search through}
\KeywordTok{var}\NormalTok{ books }\OperatorTok{=}\NormalTok{ [}\OperatorTok{\{}
  \StringTok{'ISBN'}\OperatorTok{:} \StringTok{'A'}\OperatorTok{,}
  \StringTok{'title'}\OperatorTok{:} \StringTok{"Old Man's War"}\OperatorTok{,}
  \StringTok{'author'}\OperatorTok{:} \StringTok{'John Scalzi'}
\OperatorTok{\},} \OperatorTok{\{}
  \StringTok{'ISBN'}\OperatorTok{:} \StringTok{'B'}\OperatorTok{,}
  \StringTok{'title'}\OperatorTok{:} \StringTok{'The Lock Artist'}\OperatorTok{,}
  \StringTok{'author'}\OperatorTok{:} \StringTok{'Steve Hamilton'}
\OperatorTok{\}}\NormalTok{]}

\KeywordTok{const}\NormalTok{ options }\OperatorTok{=} \OperatorTok{\{}
  \CommentTok{// Search in `author` and in `title` array}
  \DataTypeTok{keys}\OperatorTok{:}\NormalTok{ [}\StringTok{'author'}\OperatorTok{,} \StringTok{'title'}\NormalTok{]}
\OperatorTok{\}}

\CommentTok{// initialise}
\KeywordTok{const}\NormalTok{ fuse }\OperatorTok{=} \KeywordTok{new} \AttributeTok{Fuse}\NormalTok{(books}\OperatorTok{,}\NormalTok{ options)}

\CommentTok{// search 'tion' in authors and titles}
\KeywordTok{const}\NormalTok{ result }\OperatorTok{=} \VariableTok{fuse}\NormalTok{.}\AttributeTok{search}\NormalTok{(}\StringTok{'tion'}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

With some understanding of what is to be reproduced in R, we can import the library with the \texttt{source} method, which takes a \texttt{file} argument that will accept a path or URL to a JavaScript file to source. Below we use the handy CDN (Content Delivery Network) to avoid downloading a file.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{uri <-}\StringTok{ }\KeywordTok{paste0}\NormalTok{(}
  \StringTok{"https://cdnjs.cloudflare.com/ajax/"}\NormalTok{,}
  \StringTok{"libs/fuse.js/3.4.6/fuse.min.js"}
\NormalTok{)}
\NormalTok{engine}\OperatorTok{$}\KeywordTok{source}\NormalTok{(uri)}
\CommentTok{#> [1] "true"}
\end{Highlighting}
\end{Shaded}

You can think of it as using the \texttt{script} tag in HTML\index{HTML} to source (\texttt{src}) said file from disk or CDN\index{CDN}.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{<html>}
  \KeywordTok{<head>}
    \KeywordTok{<script} 
\OtherTok{      src=}\StringTok{'https://cdnjs.cloudflare.com/.../fuse.min.js'}\KeywordTok{>}
    \KeywordTok{</script>}
  \KeywordTok{</head>}
  \KeywordTok{<body>}
  \KeywordTok{</body>}
\KeywordTok{</html>}
\end{Highlighting}
\end{Shaded}

Now onto replicating the array (list) which we want to search through, the \texttt{books} object used in a previous example. As already observed, this is in essence, how V8 stores data frames in the environment\index{environment}. Below we define a data frame of books that looks similar and load it into the engine.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{books <-}\StringTok{ }\KeywordTok{data.frame}\NormalTok{(}
  \DataTypeTok{title =} \KeywordTok{c}\NormalTok{(}
    \StringTok{"Rights of Man"}\NormalTok{,}
    \StringTok{"Black Swan"}\NormalTok{,}
    \StringTok{"Common Sense"}\NormalTok{,}
    \StringTok{"Sense and Sensibility"}
\NormalTok{  ),}
  \DataTypeTok{id =} \KeywordTok{c}\NormalTok{(}\StringTok{"a"}\NormalTok{, }\StringTok{"b"}\NormalTok{, }\StringTok{"c"}\NormalTok{, }\StringTok{"d"}\NormalTok{)}
\NormalTok{)}

\NormalTok{engine}\OperatorTok{$}\KeywordTok{assign}\NormalTok{(}\StringTok{"books"}\NormalTok{, books)}
\end{Highlighting}
\end{Shaded}

Then again, we can make sure that the data frame was turned into a row-wise JSON\index{JSON} object.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{cat}\NormalTok{(engine}\OperatorTok{$}\KeywordTok{eval}\NormalTok{(}\StringTok{"JSON.stringify(books, null, 2);"}\NormalTok{))}
\CommentTok{#> [}
\CommentTok{#>   \{}
\CommentTok{#>     "title": "Rights of Man",}
\CommentTok{#>     "id": "a"}
\CommentTok{#>   \},}
\CommentTok{#>   \{}
\CommentTok{#>     "title": "Black Swan",}
\CommentTok{#>     "id": "b"}
\CommentTok{#>   \},}
\CommentTok{#>   \{}
\CommentTok{#>     "title": "Common Sense",}
\CommentTok{#>     "id": "c"}
\CommentTok{#>   \},}
\CommentTok{#>   \{}
\CommentTok{#>     "title": "Sense and Sensibility",}
\CommentTok{#>     "id": "d"}
\CommentTok{#>   \}}
\CommentTok{#> ]}
\end{Highlighting}
\end{Shaded}

Now we can define options for the search; we don't get into the details of fuse.js here as this is not the purpose of this book. You can read more about the options in the \href{https://fusejs.io/\#Examples}{examples section} of the site. We can mimic the format of the JSON options shown on the website with a simple list and assign that to a new variable in the engine. Note that we wrap the title in a \texttt{list} to ensure it is converted to an array of length 1: \texttt{list("title")} should be converted to a \texttt{{[}"title"{]}} array and not a \texttt{"title"} scalar.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{// JavaScript}
\KeywordTok{var}\NormalTok{ options }\OperatorTok{=} \OperatorTok{\{}
  \DataTypeTok{keys}\OperatorTok{:}\NormalTok{ [}\StringTok{'title'}\NormalTok{]}\OperatorTok{,}
  \DataTypeTok{id}\OperatorTok{:} \StringTok{'id'}
\OperatorTok{\}}
\end{Highlighting}
\end{Shaded}

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# R}
\NormalTok{options <-}\StringTok{ }\KeywordTok{list}\NormalTok{(}
  \DataTypeTok{keys =} \KeywordTok{list}\NormalTok{(}\StringTok{"title"}\NormalTok{),}
  \DataTypeTok{id =} \StringTok{"id"}
\NormalTok{)}

\NormalTok{engine}\OperatorTok{$}\KeywordTok{assign}\NormalTok{(}\StringTok{"options"}\NormalTok{, options)}
\end{Highlighting}
\end{Shaded}

Then we can finish the second step of the online examples, instantiate a fuse.js object with the books and options objects, then do a search, the result of which is assigned to an object which is retrieved in R with \texttt{get}.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{engine}\OperatorTok{$}\KeywordTok{eval}\NormalTok{(}\StringTok{"var fuse = new Fuse(books, options)"}\NormalTok{)}
\NormalTok{engine}\OperatorTok{$}\KeywordTok{eval}\NormalTok{(}\StringTok{"var results = fuse.search('sense')"}\NormalTok{)}
\NormalTok{engine}\OperatorTok{$}\KeywordTok{get}\NormalTok{(}\StringTok{"results"}\NormalTok{)}
\CommentTok{#> [1] "d" "c"}
\end{Highlighting}
\end{Shaded}

A search for ``sense'' returns a vector of ids where the term ``sense'' was found; \texttt{c} and \texttt{d} or the books \emph{Common Sense}, \emph{Sense and Sensibility}. We could perhaps make that last code simpler using the \texttt{call} method.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{engine}\OperatorTok{$}\KeywordTok{call}\NormalTok{(}\StringTok{"fuse.search"}\NormalTok{, }\StringTok{"sense"}\NormalTok{)}
\CommentTok{#> [1] "d" "c"}
\end{Highlighting}
\end{Shaded}

\hypertarget{v8-npm}{%
\section{NPM Packages}\label{v8-npm}}

We can also use \href{https://www.npmjs.com/}{npm} packages, though not all will work. NPM is Node's package manager, or in a sense Node's equivalent of CRAN\index{CRAN}.

To use NPM packages we need \href{http://browserify.org/}{browserify}, a node library to bundle all dependencies of an NPM package into a single file, which can subsequently be imported in V8. Browserify is itself an NPM package, and therefore requires Node.js to be installed. The reason browserify is required will be covered in more depth in chapter 20, in essence, NPM assumes disk access to load dependencies in \texttt{require()} (JavaScript) statements. This will not work with V8. Browserify will bundle all the files that comprise an NPM module into a single file that does not require disk access.

You can install browserify globally with the following the \texttt{g} flag. Once Node.js installed, browserify can be installed from the \emph{terminal} (not R console) with the \texttt{npm} command.

\begin{Shaded}
\begin{Highlighting}[]
\ExtensionTok{npm}\NormalTok{ install -g browserify}
\end{Highlighting}
\end{Shaded}

We can now ``browserify'' an npm package. To demonstrate, we will use \href{https://github.com/zeit/ms}{ms}, which converts various time formats to milliseconds. First, we install the npm package.

\begin{Shaded}
\begin{Highlighting}[]
\ExtensionTok{npm}\NormalTok{ install ms}
\end{Highlighting}
\end{Shaded}

Then we browserify it. From the terminal, the first line creates a file called \texttt{in.js} which contains \texttt{global.ms\ =\ require(\textquotesingle{}ms\textquotesingle{});} we then call browserify on that file specifying \texttt{ms.js} as output file. The \texttt{require} function in JavaScript is used to import files, \texttt{require(\textquotesingle{}ms\textquotesingle{})} imports \texttt{ms.js}, it's to some extend like \texttt{source("ms.R")}.

\begin{Shaded}
\begin{Highlighting}[]
\BuiltInTok{echo} \StringTok{"global.ms = require('ms');"} \OperatorTok{>}\NormalTok{ in.js}
\ExtensionTok{browserify}\NormalTok{ in.js -o ms.js}
\end{Highlighting}
\end{Shaded}

We can now source \texttt{ms.js} with V8. Before we do so we ought to look at example code to see what has to be reproduced using V8. Luckily the library is very straightforward: it includes a single function for all conversions, e.g.: \texttt{ms(\textquotesingle{}2\ days\textquotesingle{})} to convert two days in milliseconds.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(V8)}

\NormalTok{ms <-}\StringTok{ }\KeywordTok{v8}\NormalTok{()}
\NormalTok{ms}\OperatorTok{$}\KeywordTok{source}\NormalTok{(}\StringTok{"ms.js"}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

Then using the library simply consists of using \texttt{eval} or preferably \texttt{call} (for cleaner code and data interpretation to R).

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{ms}\OperatorTok{$}\KeywordTok{eval}\NormalTok{(}\StringTok{"ms('2 days')"}\NormalTok{)}
\CommentTok{#> [1] "172800000"}
\NormalTok{ms}\OperatorTok{$}\KeywordTok{call}\NormalTok{(}\StringTok{"ms"}\NormalTok{, }\StringTok{"2s"}\NormalTok{) }\CommentTok{# 2 seconds}
\CommentTok{#> [1] 2000}
\end{Highlighting}
\end{Shaded}

\hypertarget{v8-pkg}{%
\section{Use in Packages}\label{v8-pkg}}

In this section, we detail how one should go about using V8 in an R package. If you are not familiar with package development you can skip ahead. We start by creating a package called ``ms'' that will hold functionalities we explored in the previous section on NPM packages.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{usethis}\OperatorTok{::}\KeywordTok{create_package}\NormalTok{(}\StringTok{'ms'}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

The package is going to rely on V8 so it needs to be added under \texttt{Imports} in the \texttt{DESCRIPTION} file, then again this can be done with usethis as shown below.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# add V8 to DESCRIPTION}
\NormalTok{usethis}\OperatorTok{::}\KeywordTok{use_package}\NormalTok{(}\StringTok{"V8"}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

The package should also include the external library \texttt{ms.js} browserified from the NPM package, which should be placed it in the \texttt{inst} directory. Create it and place the \texttt{ms.js} file within the latter.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{dir.create}\NormalTok{(}\StringTok{"inst"}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

As explored, the core of the V8 package is the execution environment(s)\index{environment} that are spawned using the \texttt{v8} function. One could perhaps provide a function that returns the object created by \texttt{v8}, but it would not be convenient: this function would need to be called explicitly by the users of the package, and the output of it would need to be passed to every subsequent function. Thankfully there is a better way.

Instead, we can use the function \texttt{.onLoad}, to create the execution environment\index{environment} and import the dependency when the package is loaded by the user.

You can read more about this function in Hadley Wickham's \href{http://r-pkgs.had.co.nz/r.html}{\emph{Advanced R} book}. This is, in effect, very similar to how the Python integration of R, \href{https://rstudio.github.io/reticulate}{reticulate} \citep{R-reticulate}, is \href{https://rstudio.github.io/reticulate/articles/package.html}{used in packages}. This function is often placed in a \texttt{zzz.R} file.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# zzz.R}
\NormalTok{ms <-}\StringTok{ }\OtherTok{NULL}

\NormalTok{.onLoad <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(libname, pkgname)\{}
\NormalTok{  ms <<-}\StringTok{ }\NormalTok{V8}\OperatorTok{::}\KeywordTok{v8}\NormalTok{()}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

At this stage the package's directory structure should look similar to the tree below.

\begin{Shaded}
\begin{Highlighting}[]
\ExtensionTok{.}
\NormalTok{├── }\ExtensionTok{DESCRIPTION}
\NormalTok{├── }\ExtensionTok{NAMESPACE}
\NormalTok{├── }\ExtensionTok{R}
\NormalTok{│   └── }\ExtensionTok{zzz.R}
\NormalTok{└── }\ExtensionTok{inst}
\NormalTok{    └── }\ExtensionTok{ms.js}
\end{Highlighting}
\end{Shaded}

Now the dependency\index{dependency} can be sourced in the \texttt{.onLoad} function. We can locate the files in the \texttt{inst} directory with the \texttt{system.file} function.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# zzz.R}
\NormalTok{ms <-}\StringTok{ }\OtherTok{NULL}

\NormalTok{.onLoad <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(libname, pkgname)\{}
\NormalTok{  ms <<-}\StringTok{ }\NormalTok{V8}\OperatorTok{::}\KeywordTok{v8}\NormalTok{()}

  \CommentTok{# locate dependency file}
\NormalTok{  dep <-}\StringTok{ }\KeywordTok{system.file}\NormalTok{(}\StringTok{"ms.js"}\NormalTok{, }\DataTypeTok{package =} \StringTok{"ms"}\NormalTok{)}
\NormalTok{  ms}\OperatorTok{$}\KeywordTok{source}\NormalTok{(dep)}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

We can then create a \texttt{to\_ms} function. It will have access to the \texttt{ms} object we instantiated in \texttt{.onLoad}.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{#' @export}
\NormalTok{to_ms <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(string)\{}
\NormalTok{  ms}\OperatorTok{$}\KeywordTok{call}\NormalTok{(}\StringTok{"ms"}\NormalTok{, string)}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

After running \texttt{devtools::document()} and installing the package with \texttt{devtools::install()}, it's ready to be used.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{ms}\OperatorTok{::}\KeywordTok{to_ms}\NormalTok{(}\StringTok{"10 hrs"}\NormalTok{)}
\CommentTok{#> [1] 36000000}
\end{Highlighting}
\end{Shaded}

\hypertarget{v8-ml}{%
\chapter{Machine Learning}\label{v8-ml}}

In this chapter, we build a package that, via V8, wraps \href{https://github.com/mljs/ml}{ml.js}, a library that brings machine learning to JavaScript. It covers quite a few models; we only include one: the linear regression. This is an interesting example because it reveals some proceedings that one is likely to run into when creating packages using V8.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{const}\NormalTok{ x }\OperatorTok{=}\NormalTok{ [}\FloatTok{0.5}\OperatorTok{,} \DecValTok{1}\OperatorTok{,} \FloatTok{1.5}\OperatorTok{,} \DecValTok{2}\OperatorTok{,} \FloatTok{2.5}\NormalTok{]}\OperatorTok{;}
\KeywordTok{const}\NormalTok{ y }\OperatorTok{=}\NormalTok{ [}\DecValTok{0}\OperatorTok{,} \DecValTok{1}\OperatorTok{,} \DecValTok{2}\OperatorTok{,} \DecValTok{3}\OperatorTok{,} \DecValTok{4}\NormalTok{]}\OperatorTok{;}

\KeywordTok{const}\NormalTok{ regression }\OperatorTok{=} \KeywordTok{new} \VariableTok{ml}\NormalTok{.}\AttributeTok{SimpleLinearRegression}\NormalTok{(x}\OperatorTok{,}\NormalTok{ y)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

\hypertarget{v8-ml-dependency}{%
\section{Dependency}\label{v8-ml-dependency}}

We start by creating a package and add the V8 package as dependency\index{dependency}.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{usethis}\OperatorTok{::}\KeywordTok{create_package}\NormalTok{(}\StringTok{"ml"}\NormalTok{)}
\NormalTok{usethis}\OperatorTok{::}\KeywordTok{use_package}\NormalTok{(}\StringTok{"V8"}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

Then we create the \texttt{inst} directory in which we place the ml.js file downloaded from the CDN.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{dir.create}\NormalTok{(}\StringTok{"inst"}\NormalTok{)}
\KeywordTok{download.file}\NormalTok{(}
  \StringTok{"https://www.lactame.com/lib/ml/4.0.0/ml.min.js"}\NormalTok{, }
  \StringTok{"inst/ml.min.js"}
\NormalTok{)}
\end{Highlighting}
\end{Shaded}

With the dependency\index{dependency} downloaded, one can start working on the R code. First, a new V8 context needs to be created and the ml.js file needs to be imported into it.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# zzz.R}
\NormalTok{ml <-}\StringTok{ }\OtherTok{NULL}

\NormalTok{.onLoad <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(libname, pkgname)\{}
\NormalTok{  ml <<-}\StringTok{ }\NormalTok{V8}\OperatorTok{::}\KeywordTok{v8}\NormalTok{()}
\NormalTok{  mljs <-}\StringTok{ }\KeywordTok{system.file}\NormalTok{(}\StringTok{"ml.min.js"}\NormalTok{, }\DataTypeTok{package =} \StringTok{"ml"}\NormalTok{)}
\NormalTok{  ml}\OperatorTok{$}\KeywordTok{source}\NormalTok{(mljs)}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

\hypertarget{v8-ml-regression}{%
\section{Simple Regression}\label{v8-ml-regression}}

The \href{https://github.com/mljs/regression-simple-linear}{``simple linear regression''} consists of a simple function that takes two arrays. We can thus create a function that takes two vectors, \texttt{x}, and \texttt{y}, and runs the regression.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{#' @export }
\NormalTok{ml_simple_lm <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(y, x)\{}
  \CommentTok{# assign x and y}
\NormalTok{  ml}\OperatorTok{$}\KeywordTok{assign}\NormalTok{(}\StringTok{"x"}\NormalTok{, x)}
\NormalTok{  ml}\OperatorTok{$}\KeywordTok{assign}\NormalTok{(}\StringTok{"y"}\NormalTok{, y)}

  \CommentTok{# run regression}
\NormalTok{  ml}\OperatorTok{$}\KeywordTok{eval}\NormalTok{(}
    \StringTok{"var regression = new ML.SimpleLinearRegression(x, y);"}
\NormalTok{  )}
  
  \CommentTok{# return results}
\NormalTok{  ml}\OperatorTok{$}\KeywordTok{get}\NormalTok{(}\StringTok{"regression"}\NormalTok{)}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

Then we can document and load the model to the function.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{ml_simple_lm}\NormalTok{(cars}\OperatorTok{$}\NormalTok{speed, cars}\OperatorTok{$}\NormalTok{dist)}
\CommentTok{## $name}
\CommentTok{## [1] "simpleLinearRegression"}
\CommentTok{## }
\CommentTok{## $slope}
\CommentTok{## [1] 0.1655676}
\CommentTok{## }
\CommentTok{## $intercept}
\CommentTok{## [1] 8.283906}
\end{Highlighting}
\end{Shaded}

This works but has a few issues, namely running two or more regression internally will override the variable \texttt{regression} in the V8 context. Let us demonstrate by implementing a function to predict.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{#' @export}
\NormalTok{ml_predict <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(x)\{}
\NormalTok{  ml}\OperatorTok{$}\KeywordTok{call}\NormalTok{(}\StringTok{"regression.predict"}\NormalTok{, x)}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

We then document and load the functions to run two regressions in a row then observe the issue. Unlike R, the model we created only exists in JavaScript, unlike the \texttt{lm}, the function \texttt{ml\_simple\_lm} does not return the model. Therefore, \texttt{ml\_simple\_lm} does not distinguish between models, unlike \texttt{predict}, which takes the model as the first argument and runs the prediction on it.

This implementation of ml.js is indeed very dangerous.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# first model}
\KeywordTok{ml_simple_lm}\NormalTok{(cars}\OperatorTok{$}\NormalTok{speed, cars}\OperatorTok{$}\NormalTok{dist)}
\KeywordTok{ml_predict}\NormalTok{(}\DecValTok{15}\NormalTok{)}
\CommentTok{## 25.18405}

\CommentTok{# overrides model}
\KeywordTok{ml_simple_lm}\NormalTok{(}\DecValTok{1}\OperatorTok{:}\DecValTok{10}\NormalTok{, }\KeywordTok{runif}\NormalTok{(}\DecValTok{10}\NormalTok{))}

\CommentTok{# produces different predictions}
\KeywordTok{ml_predict}\NormalTok{(}\DecValTok{15}\NormalTok{)}
\CommentTok{## 10.76742}
\end{Highlighting}
\end{Shaded}

The package ml currently under construction should emulate R in that respect; the \texttt{ml\_simple\_lm} should return the model, which should be usable with the \texttt{predict} function. In order to do so, we are going to need to track regressions internally in V8 so the \texttt{ml\_simple\_lm} returns a proxy of the model that \texttt{predict} can use to predict on the intended model.

In order to track and store regressions internally, we are going to declare an empty array when the package is loaded.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{# zzz.R}
\NormalTok{ml <-}\StringTok{ }\OtherTok{NULL}

\NormalTok{.onLoad <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(libname, pkgname)\{}
\NormalTok{  ml <<-}\StringTok{ }\NormalTok{V8}\OperatorTok{::}\KeywordTok{v8}\NormalTok{()}
\NormalTok{  mljs <-}\StringTok{ }\KeywordTok{system.file}\NormalTok{(}\StringTok{"ml.min.js"}\NormalTok{, }\DataTypeTok{package =} \StringTok{"ml"}\NormalTok{)}
\NormalTok{  ml}\OperatorTok{$}\KeywordTok{source}\NormalTok{(mljs)}
\NormalTok{  ml}\OperatorTok{$}\KeywordTok{eval}\NormalTok{(}\StringTok{"var regressions = [];"}\NormalTok{)}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

Then, one can track regressions by creating an R object, which is incremented every time \texttt{ml\_simple\_lm} runs; this can be used as a variable name in the JavaScript \texttt{regressions} array declare in \texttt{.onLoad}. This variable name must be stored in the object we intend to return so the \texttt{predict} method we will create later on can access the model and run predictions. Finally, in order to declare a new method on the \texttt{predict} function, we need to return an object bearing a unique class. Below we use \texttt{mlSimpleRegression}.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{counter <-}\StringTok{ }\KeywordTok{new.env}\NormalTok{(}\DataTypeTok{parent =} \KeywordTok{emptyenv}\NormalTok{())}
\NormalTok{counter}\OperatorTok{$}\NormalTok{regressions <-}\StringTok{ }\DecValTok{0}

\CommentTok{#' @export }
\NormalTok{ml_simple_lm <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(y, x)\{}
\NormalTok{  counter}\OperatorTok{$}\NormalTok{regressions <-}\StringTok{ }\NormalTok{counter}\OperatorTok{$}\NormalTok{regressions }\OperatorTok{+}\StringTok{ }\DecValTok{1}

  \CommentTok{# assign variables}
\NormalTok{  ml}\OperatorTok{$}\KeywordTok{assign}\NormalTok{(}\StringTok{"x"}\NormalTok{, x)}
\NormalTok{  ml}\OperatorTok{$}\KeywordTok{assign}\NormalTok{(}\StringTok{"y"}\NormalTok{, y)}

  \CommentTok{# address}
\NormalTok{  address <-}\StringTok{ }\KeywordTok{paste0}\NormalTok{(}\StringTok{"regressions['"}\NormalTok{, counter}\OperatorTok{$}\NormalTok{regressions, }\StringTok{"']"}\NormalTok{)}

  \CommentTok{# create regression}
\NormalTok{  code <-}\StringTok{ }\KeywordTok{paste0}\NormalTok{(}
\NormalTok{    address, }\StringTok{" = new ML.SimpleLinearRegression(x, y);"}
\NormalTok{  )}
\NormalTok{  ml}\OperatorTok{$}\KeywordTok{eval}\NormalTok{(code)}

  \CommentTok{# retrieve and append address}
\NormalTok{  regression <-}\StringTok{ }\NormalTok{ml}\OperatorTok{$}\KeywordTok{get}\NormalTok{(address)}
\NormalTok{  regression}\OperatorTok{$}\NormalTok{address <-}\StringTok{ }\NormalTok{address}

  \CommentTok{# create object of new class}
  \KeywordTok{structure}\NormalTok{(}
\NormalTok{    regression, }
    \DataTypeTok{class =} \KeywordTok{c}\NormalTok{(}\StringTok{"mlSimpleRegression"}\NormalTok{, }\KeywordTok{class}\NormalTok{(regression))}
\NormalTok{  )}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

Then one can implement the \texttt{predict} method for \texttt{mlSimpleRegression}. The function uses the \texttt{address} of the model to run the JavaScript \texttt{predict} method on that object.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{#' @export }
\NormalTok{predict.mlSimpleRegression <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(object, newdata, ...)\{}
\NormalTok{  code <-}\StringTok{ }\KeywordTok{paste0}\NormalTok{(object}\OperatorTok{$}\NormalTok{address, }\StringTok{".predict"}\NormalTok{)}
\NormalTok{  ml}\OperatorTok{$}\KeywordTok{call}\NormalTok{(code, newdata)}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

We can then build and load the package to it in action.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(ml)}

\CommentTok{# first model}
\NormalTok{model_cars <-}\StringTok{ }\KeywordTok{ml_simple_lm}\NormalTok{(cars}\OperatorTok{$}\NormalTok{speed, cars}\OperatorTok{$}\NormalTok{dist)}

\CommentTok{# second model}
\NormalTok{model_random <-}\StringTok{ }\KeywordTok{ml_simple_lm}\NormalTok{(}\DecValTok{1}\OperatorTok{:}\DecValTok{10}\NormalTok{, }\KeywordTok{runif}\NormalTok{(}\DecValTok{10}\NormalTok{))}

\KeywordTok{predict}\NormalTok{(model_random, }\DecValTok{15}\NormalTok{)}
\CommentTok{#> [1] -130.8514}
\KeywordTok{predict}\NormalTok{(model_cars, }\DecValTok{15}\NormalTok{)}
\CommentTok{#> [1] 10.76742}
\end{Highlighting}
\end{Shaded}

\hypertarget{v8-ml-exercises}{%
\section{Exercises}\label{v8-ml-exercises}}

There are too many great JavaScript libraries that would be great additions to the R ecosystem but perhaps try and integrate one of these below. They are simple yet exciting and thus provide ideal first forays into what this part of the book explained.

\begin{itemize}
\tightlist
\item
  \href{https://github.com/chancejs/chancejs}{chance.js} - random generator
\item
  \href{https://github.com/scurker/currency.js}{currency.js} - helpers to work with currencies
\end{itemize}

\hypertarget{part-robust-javascript}{%
\part{Robust JavaScript}\label{part-robust-javascript}}

\hypertarget{webpack-intro}{%
\chapter{Managing JavaScript}\label{webpack-intro}}

Thus far, all of the JavaScript code written in this book was placed directly in the file that was imported in the front end, be it htmlwidgets or Shiny-related code. While this works for the smaller projects, it is bound to lead to headaches for the larger ones.

It's the same problem one faces when writing R code. While a small script of 300 lines of code will do the job, a large script of 10,000 lines quickly becomes unmanageable. Therefore when tackling more extensive projects, the R programmer will turn to solutions that enforce a specific file structure and provide utilities to harmonise how those files work together. Some of these solutions may include the drake \citep{R-drake} or targets \citep{R-targets} packages, both of which provide tools to manage complex workflows. Another method often used is to build the project as an R package, thereby enforcing a particular structure and enabling reproducibility, unit tests, and more.

The issues mentioned above are also a concern in JavaScript, though here one has to consider additional pitfalls. Like R, JavaScript is a continually evolving language, but while R code written on version \texttt{4.0.0} will likely run fine on version \texttt{3.0.0}, it is not precisely the case for JavaScript. As the language evolves and changes, web browsers have to keep up to support any new feature brought by new releases.

Therefore JavaScript code that is written on the latest version may not run on all browsers. Also, consider that even if the latest versions of Google Chrome and Mozilla Firefox tend to support the latest JavaScript, users who visit your Shiny applications or use your htmlwidgets may not have their browsers up to date.

In JavaScript, code mismanagement might be exacerbated because it often relies on other files such as CSS, JSON, images, and more, making it challenging to build robust projects. Moving an image from one folder to another or removing a CSS file may break an entire JavaScript project.

Also, in JavaScript, code size matters: the smaller the file, the faster it will load in the browser. JavaScript files are reduced in size with a process called ``minification,'' which consists of removing all unnecessary characters, such as spaces, from a JavaScript file to obtain a ``minified'' version that fits on a single line, which is smaller in size. This is because humans cannot read or write minified code; try removing all line breaks and spaces from your R scripts if you think otherwise, then imagine JavaScript minification takes it a step further.

Finally, since R is rather strict, packages enforce a specific structure; JavaScript does not come with such restrictions off the shelf. Therefore, it's even more tempting for the developer to take shortcuts and make a mess of their projects.

Combine all of the above and software that involves JavaScript can quickly become poorly structured and cumbersome. Moreover, considering all these potential issues as one writes code is unsustainable as it dramatically increases the cognitive load and ultimately distracts from writing code itself: it's just too much to consider. Thankfully some tools have been invented over the years to help JavaScript developers manage all of these matters. These tools differ slightly from one another, they each have their pros and cons, but all have the same goal: making JavaScript projects more robust and manageable.

\href{https://gruntjs.com/}{Grunt} describes itself as a ``the JavaScript task runner,'' and will carry minification, compilation, unit testing, linting, and more. There is also \href{https://parceljs.org/}{Parcel} a web application bundler that will minify and bundle (and more) JavaScript code. However, the one we shall use in this part of the book is \href{https://webpack.js.org/}{webpack}, as it is very similar to Grunt and is one of the most popular.

\hypertarget{webpack-example}{%
\section{Example}\label{webpack-example}}

There are admittedly few R packages that make use of such technology, though it must be said that many could greatly benefit from it. Given its size and complexity a package such as Shiny, however, could probably not do without it.

Shiny makes use of Grunt, the source code that comprises all of the JavaScript required to run the front end (inputs, outputs, modals, etc.) is in the \texttt{srcjs} directory which can be found on the \href{https://github.com/rstudio/shiny}{official GitHub repository.} This folder includes a multitude of JavaScript files the names of which indicate the code they encompass; \texttt{input\_binding\_checkbox.js}, \texttt{modal.js}, etc.

These files are processed by Grunt which, using the \texttt{Gruntfile.js} configuration file in the \texttt{tools} directory, creates multiple bundles that it places in the \texttt{inst} folder of the package.

\hypertarget{webpack-browser}{%
\section{Transpiling}\label{webpack-browser}}

As new functionalities are made available in JavaScript, with every modern version web browsers\index{web browser} have to keep pace and support running said functionalities. First, this is not always the case, major web browsers such as Google Chrome, Mozilla Firefox, and Safari generally do a decent job of keeping up, but one can never count on the individuals using those to do keep their browsers up to date.

Imagine building a large htmlwidgets for a client only to discover that for IT security reasons all their company laptops run a particular version of a web browser that does not support critical functionalities the widget relies upon.

Ensuring that the JavaScript code can run on most browsers is no trivial task. The best way to do so \emph{is not} to write outdated JavaScript code that all browsers should support, the solution is actually to use a \href{https://babeljs.io/}{Babel.} This transpiler will convert ``ECMAScript 2015+\index{ECMA} code into a backwards-compatible version of JavaScript.'' This way one can use the latest JavaScript, even before browsers officially support it, and transpile it with Babel to obtain a JavaScript file that will run on any browser that supports ECMAScript 2015\index{ECMA} (JavaScript version released in 2015).

\hypertarget{webpack-minification}{%
\section{Minification}\label{webpack-minification}}

Web browsers\index{web browser} always need to load the files necessary to render a webpage, be it a static website, a Shiny application, or a standalone widget. Loading those files can take critical time and make the loading of a web application slow. Therefore it is good practice to reduce the size of those files. This includes compressing images, so they are smaller in size and load faster but also ``minifying'' CSS and JavaScript code.

When writing code, us humans like to use comprehensible variable names, line breaks, spaces, and other things that help make things clear and readable. Machines, however, do not need any of that; as long as the code is valid, it will run.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{// global variable}
\KeywordTok{let}\NormalTok{ number }\OperatorTok{=} \DecValTok{41}\OperatorTok{;}

\CommentTok{// my hello function}
\KeywordTok{function} \AttributeTok{hello}\NormalTok{(my_variable)}\OperatorTok{\{}
    \KeywordTok{let}\NormalTok{ total }\OperatorTok{=}\NormalTok{ number }\OperatorTok{+}\NormalTok{ my_variable}\OperatorTok{;}
    \VariableTok{console}\NormalTok{.}\AttributeTok{log}\NormalTok{(total)}\OperatorTok{;}
\OperatorTok{\}}
\end{Highlighting}
\end{Shaded}

Minification is the process of removing all of the ``syntactic sugar'' that is unnecessary to obtain JavaScript code that fits in a single line and makes for a smaller file. See the example given here where the code above is minified to get the code below, note that the comment was removed and even some variable names have changed to be shorter.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{let}\NormalTok{ number}\OperatorTok{=}\DecValTok{41}\OperatorTok{;}\KeywordTok{function} \AttributeTok{hello}\NormalTok{(e)}\OperatorTok{\{}\KeywordTok{let}\NormalTok{ l}\OperatorTok{=}\NormalTok{number}\OperatorTok{+}\NormalTok{e}\OperatorTok{;}\VariableTok{console}\NormalTok{.}\AttributeTok{log}\NormalTok{(l)}\OperatorTok{\}}
\end{Highlighting}
\end{Shaded}

The minified files of a library tend to end in \texttt{.min.js} though minified code can very well be placed in a \texttt{.js} file.

\hypertarget{webpack-structure}{%
\section{Bundling and Modules}\label{webpack-structure}}

Managing the structure of JavaScript projects can be tricky. One does not want to place 2,000 lines of code in a single file, but splitting JavaScript code into multiple files is complicated.

While writing an R package, one is free to organise the functions in different files as their content (functions, data, etc.) is ultimately loaded into the global \index{environment} with \texttt{library} by the user of the package.

In JavaScript, one does not have the luxury of writing code across different files to then call \texttt{library()} in the web browser, so all the functions, and variables are available. In this paradigm, individual files have to be loaded separately in the browser (as shown below).

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{<script}\OtherTok{ src=}\StringTok{"utils.js"}\KeywordTok{></script>}
\KeywordTok{<script}\OtherTok{ src=}\StringTok{"main.js"}\KeywordTok{></script>}
\end{Highlighting}
\end{Shaded}

While this may be fine for two or three files, it quickly gets out of hand as one has to remember to import those in the correct order. In the above example, variables declared in \texttt{main.js} cannot be used in \texttt{utils.js}, unless we change the order of the import in which case something else will likely break.

It's therefore essential to use tools that allow splitting JavaScript programs into modules (to write programs in different files), manage the dependencies\index{dependency} between these files, then ``bundle'' those correctly into one or more files destined to be imported in the browser.

\hypertarget{webpack-decouple}{%
\section{Decoupling}\label{webpack-decouple}}

One thing that might become apparent from the previous sections is the idea of decoupling the final code that makes it into the web browser from the code we write. It is thanks to this decoupling that we can write easy-to-read JavaScript code on the latest version across multiple files to then run the various processes of transpiling, bundling, and minifying to obtain code that is more efficient and robust for the browser.

This may appear like a lot to manage. Thankfully we can use the aforementioned webpack software to take care of all these procedures for us. There is nonetheless a gentle learning curve to make use of it as it involves multiple new concepts.

Moreover, webpack does not limit itself to the previously-mentioned processes. It will also take care of other things such as removing ``dead code,'' functions or variables that are declared but not used, and it allows integrating CSS and other files in JavaScript itself, and so much more.

\hypertarget{webpack-npm}{%
\section{NPM}\label{webpack-npm}}

Another new piece of software that we need to be introduce is Node's Package Manager, hereafter referred to as NPM. As indicated by the name, it's a package manager for Node.js, or translated for the R user it's Node's loose equivalent of CRAN\index{CRAN}. One first significant difference is that while CRAN\index{CRAN} performs very rigorous checks on any package submitted, NPM does not; one can publish almost anything.

Notice how every dependency\index{dependency} used in this book had to be either found through a CDN\index{CDN} or manually downloaded, only to be imported in the final document. Again, this is useful for the smaller projects but may become a hindrance when multiple dependencies have to be managed and updated, added and removed, etc.

NPM has wholly changed how dependencies can be managed and imported in JavaScript. It is designed for Node.js code, but many (if not all) libraries that are meant to run in web browsers\index{web browser} are published on NPM: it's just too convenient.

NPM, combined with the decoupling, and bundling covered in previous sections, enables managing dependencies\index{dependency} much more sensibly, and efficiently. So one can, for instance, import only certain functions from an external library rather than the whole, thereby further reducing the size of the final bundle of JavaScript files.

\hypertarget{webpack-conclude}{%
\section{With R}\label{webpack-conclude}}

To be clear, it's not always necessary to involve webpack and NPM into a project; these can take some time to set up and be excessive for a smaller project. It's good to be familiar with them as one might want to make use of those in larger projects.

Webpack and NPM were not designed with R in mind, so there are some potential issues to consider when using it in packages and Shiny applications.

In the following chapter, we discover how to include both webpack and NPM to make more robust Shiny applications, widgets, and other packages that involve JavaScript.

\hypertarget{webpack-intro-discover}{%
\chapter{Discover Webpack and NPM}\label{webpack-intro-discover}}

In this chapter, we discover how to feature webpack and NPM in a straightforward Shiny project. The idea is not to build a complex application, only to find out how one might go about bringing them into an R project and observe some of their benefits (and potential issues).

There is a lot of depth to NPM and webpack; we only touch upon the surface here so we can obtain a basic setup for a Shiny application. We'll eventually go into slightly more detail as this part of the book progresses, but it will by no means fully explore the realm of webpack. It's always a good idea to take a look at the \href{https://webpack.js.org/}{official documentation} to get a better picture of the technology.

\hypertarget{webpack-intro-install}{%
\section{Installation}\label{webpack-intro-install}}

As Node's Package Manager, a working installation of Node.js, is required, NPM ships with it. A bit like R in a sense where the package manager also comes with the language, install R, and you can install packages from CRAN\index{CRAN} with \texttt{install.packages}. The same applies here, install Node and you can install NPM packages from the command line.

\begin{rmdnote}
We are only going to use Node.js \emph{indirectly}, some of its
functionalities and its package manager. This is not about building Node
applications.
\end{rmdnote}

Below are some directions on how to install Node.js. In the event this does not work or you encounter issues please refer to the \href{https://nodejs.org/en/}{official website}.

\hypertarget{webpack-intro-install-mac}{%
\subsection{Mac OS}\label{webpack-intro-install-mac}}

On Mac OS, the easiest way is via homebrew.

\begin{verbatim}
brew update
brew install node
\end{verbatim}

Otherwise there is also an \href{https://nodejs.org/en/download/}{installer} available.

\hypertarget{webpack-intro-install-ubuntu}{%
\subsection{Ubuntu}\label{webpack-intro-install-ubuntu}}

With Ubuntu one can install it straight from the package manager.

\begin{verbatim}
sudo apt install nodejs
\end{verbatim}

\hypertarget{webpack-intro-install-windows}{%
\subsection{Windows}\label{webpack-intro-install-windows}}

Download and install the official \href{https://nodejs.org/en/download/}{executable} or use \href{https://chocolatey.org/}{chocolatey}.

\begin{verbatim}
cinst nodejs.install
\end{verbatim}

Or use \href{https://scoop.sh/}{scoop}.

\begin{verbatim}
scoop install nodejs
\end{verbatim}

\hypertarget{webpack-intro-install-other}{%
\subsection{Other}\label{webpack-intro-install-other}}

If you are on another OS or Linux distro check the official, very concise \href{https://nodejs.org/en/download/package-manager/}{guide} to install from various package managers.

\hypertarget{webpack-intro-setup}{%
\section{Set Up the App}\label{webpack-intro-setup}}

Let us first put together a simple Shiny application that will serve as a basis for including webpack and npm. Create a new directory and in it place a file called \texttt{app.R} containing a very simple application.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(shiny)}

\NormalTok{ui <-}\StringTok{ }\KeywordTok{fluidPage}\NormalTok{(}
  \KeywordTok{h1}\NormalTok{(}\StringTok{"A shiny app"}\NormalTok{)}
\NormalTok{)}

\NormalTok{server <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(...) \{\}}

\KeywordTok{shinyApp}\NormalTok{(ui, server)}
\end{Highlighting}
\end{Shaded}

\hypertarget{webpack-intro-init-npm}{%
\section{Initialise NPM}\label{webpack-intro-init-npm}}

With a simple application, one can initialise NPM. This could be translated into the equivalent of starting a new project in R. This is done from the command line, \emph{from the root of the directory} that you want to use as a project.

Whereas in R we previously used the usethis package to create packages with \texttt{create\_package} or projects with \texttt{create\_project}, NPM does not create the initial empty directory where the project will be created; you have to create the directory first then initialise a new project.

An NPM project can be initialised with the command \texttt{npm\ init}, which when run prompts the user with a few questions, such as the name of the project, the license to use, etc. These have little importance for what we do here but will matter if you decide to publish the package on NPM. One can also pass the ``yes'' flag to the function to skip those questions: \texttt{npm\ init\ -y}.

This creates a \texttt{package.json} file, which is loosely equivalent to the \texttt{DESCRIPTION} of an R package; it includes information on the dependencies\index{dependency} of the project, the version of the project, and more.

We will revisit this file later in the chapter. At this stage ensure you have run \texttt{npm\ init} (with or without the \texttt{-y} flag) from the root of the project (where the \texttt{app.R} file is located).

\hypertarget{webpack-intro-install-pkgs}{%
\section{Installing NPM Packages}\label{webpack-intro-install-pkgs}}

Unless the R programmer uses packages such as renv \citep{R-renv} or packrat \citep{R-packrat} then packages are installed globally on the machine, running \texttt{install.packages("dplyr")} installs a single version of dplyr across the entire device. Because CRAN\index{CRAN} is strict and its packages subsequently stable, it tends not to be too much of an issue. Packages submitted to \index{CRAN} are checked for reverse dependencies\index{dependency} (other packages that depend on it) to see if the submission could cause problems downstream.

However, NPM does no such thing with packages that are submitted. Therefore the developer has to be more careful about dependencies\index{dependency}, particularly versioning as packages can dramatically change from one version to the next. Thus it makes sense that NPM out-of-the-box advocates and provides tools to encapsulate projects. It is \emph{not recommended,} to install NPM packages globally. NPM projects (the directory where \texttt{npm\ init} was run) come bundled with the equivalent of renv/packrat.

Installing Node packages also takes place at the command line with the \texttt{install} command followed by the name of the package to install, e.g.: \texttt{npm\ install\ nameOfPackage}.

As mentioned, it is rarely a good idea to install packages globally at the exception of very few packages, such as command-line applications used across the machine. As an example, the \href{https://docsify.js.org/}{docsify-cli} package for documentation generation can safely be installed globally as it is used at the command line in projects that don't necessarily use NPM. This can be achieved with the \texttt{-g} flag that stands for ``global'': \texttt{npm\ install\ docsify-cli\ -g}.

There are two other scopes on which packages can be installed. NPM allows distinguishing between packages that are needed to develop the project and packages that are needed in the final product being built.

R does not come with such convenience but it could perhaps be useful. For instance throughout the book we used the usethis package to develop packages from setting it up to adding packages to the \texttt{DESCRIPTION} file, and more. Perhaps one would like to make this a ``developer'' dependency\index{dependency} so that other developers that pull the package from GitHub have usethis installed and readily available. The advantage is that this dependency would not be included in the final product, that is, usethis is not required to use the package (only to develop it) and therefore is not installed by the user.

As stated in the previous chapter, file size matters in JavaScript; it is, therefore, crucial that dependencies\index{dependency} that are used only for development are not included in the final JavaScript file. With NPM this can be done by using the \texttt{-\/-save-dev} flag, e.g.: \texttt{npm\ install\ webpack\ -\/-save-dev} to install webpack. This is how it will be eventually installed as it is needed to prepare the final product (minify, bundle, etc.) but is not required to run the bundled file(s).

Finally, there are the ``true'' dependencies, those that are needed in the output we're creating. For instance, were we to rebuild the gio widget using NPM we could install it with \texttt{npm\ install\ giojs\ -\/-save} because this dependency\index{dependency} will be required in the output file we produce.

Before moving on to the next section, let us install webpack and its command-line interface as developer dependencies\index{dependency}.

\begin{Shaded}
\begin{Highlighting}[]
\ExtensionTok{npm}\NormalTok{ install webpack webpack-cli --save-dev}
\end{Highlighting}
\end{Shaded}

Notice that this updated the \texttt{package.json} file and created the \texttt{package-lock.json} file as well as a \texttt{node\_modules} directory to obtain the following structure.

\begin{verbatim}
.
├── app.R
├── node_modules
├── package-lock.json
└── package.json
\end{verbatim}

The directory \texttt{node\_modules} actually holds all the dependencies, and it will grow in size as you add more, it's important that this directory is not pushed to whatever version control system you happen use (GitHub, Bitbucket, Gitlab).

\begin{rmdnote}
Exclude the \texttt{node\_modules} directory from your version control
(Git or otherwise)
\end{rmdnote}

The dependencies are anyway not needed as one can pull the project without the \texttt{node\_modules} then from the root of the project run \texttt{npm\ install} to install the dependencies\index{dependency} that are listed in the \texttt{package.json} file. We can indeed observe that this file was updated to include \texttt{webpack} and \texttt{webpack-cli} as \texttt{devDependencies}, at the bottom of the file.

\begin{Shaded}
\begin{Highlighting}[]
\FunctionTok{\{}
  \DataTypeTok{"name"}\FunctionTok{:} \StringTok{"name-of-your-project"}\FunctionTok{,}
  \DataTypeTok{"version"}\FunctionTok{:} \StringTok{"1.0.0"}\FunctionTok{,}
  \DataTypeTok{"description"}\FunctionTok{:} \StringTok{""}\FunctionTok{,}
  \DataTypeTok{"main"}\FunctionTok{:} \StringTok{"index.js"}\FunctionTok{,}
  \DataTypeTok{"scripts"}\FunctionTok{:} \FunctionTok{\{}
    \DataTypeTok{"test"}\FunctionTok{:} \StringTok{"echo }\CharTok{\textbackslash{}"}\StringTok{Error: no test specified}\CharTok{\textbackslash{}"}\StringTok{ && exit 1"}
  \FunctionTok{\},}
  \DataTypeTok{"keywords"}\FunctionTok{:} \OtherTok{[]}\FunctionTok{,}
  \DataTypeTok{"author"}\FunctionTok{:} \StringTok{""}\FunctionTok{,}
  \DataTypeTok{"license"}\FunctionTok{:} \StringTok{"ISC"}\FunctionTok{,}
  \DataTypeTok{"devDependencies"}\FunctionTok{:} \FunctionTok{\{}
    \DataTypeTok{"webpack"}\FunctionTok{:} \StringTok{"^5.2.0"}\FunctionTok{,}
    \DataTypeTok{"webpack-cli"}\FunctionTok{:} \StringTok{"^4.1.0"}
  \FunctionTok{\}}
\FunctionTok{\}}
\end{Highlighting}
\end{Shaded}

The \texttt{package-lock.json} file is automatically generated and \emph{should not be edited manually.} It describes the exact tree of all the dependencies. If you installed a package by mistake, you could uninstall it with \texttt{npm\ uninstall\ nameOfPage}.

\textbf{Recap}

\begin{itemize}
\tightlist
\item
  Install packages globally with \texttt{npm\ install\ package\ -g}
\item
  Install developer dependencies\index{dependency} with \texttt{npm\ install\ package\ -\/-save-dev}
\item
  Install dependencies required in the output with \texttt{npm\ install\ package\ -\/-save}
\item
  Uninstall packages with \texttt{npm\ uninstall\ package}
\end{itemize}

\hypertarget{webpack-intro-entry-points}{%
\section{Entry Point and Output}\label{webpack-intro-entry-points}}

In general, an NPM project with webpack will make use of an \texttt{src} directory where the source code is placed and a \texttt{dist} directory (for distributed) where the bundled source code will be placed; we'll see how to change these defaults later on. It will eventually be necessary as the \texttt{src} directory in R packages is reserved for compiled code (e.g., C++) and therefore cannot be used to place JavaScript files.

It will not be a problem here as we are not building a package.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{dir.create}\NormalTok{(}\StringTok{"src"}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

Webpack will then require at least one ``entry point.'' An entry point is an input file in the \texttt{src} directory that webpack will use as a source to produce the bundle. Let's create the go-to ``hello world'' of JavaScript; the snippet below creates the \texttt{index.js} file with a basic vanilla JavaScript alert.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{writeLines}\NormalTok{(}\StringTok{"alert('hello webpack!')"}\NormalTok{, }\StringTok{"src/index.js"}\NormalTok{) }
\end{Highlighting}
\end{Shaded}

The next section on configuration will detail precisely how to indicate to webpack that this is indeed the entry point it should use.

\hypertarget{webpack-intro-conf}{%
\section{Configuration File}\label{webpack-intro-conf}}

Webpack comes with a configuration file, \texttt{webpack.config.js}. Though for a larger project it is advised to split it into multiple configuration files (more on that later). This file can include numerous options, plugins, and other settings to customise how webpack transforms the entry point into an output, only some of which will be explored in this book as there are too many to cover.

Below is probably the most straightforward configuration file one may create. At the bare minimum, the configuration file will need to have an entry point specified; in this case, the previously-created \texttt{index.js} file. If no \texttt{output} path is specified, then webpack will produce it at \texttt{dist/main.js} automatically.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{// webpack.config.js}
\VariableTok{module}\NormalTok{.}\AttributeTok{exports} \OperatorTok{=} \OperatorTok{\{}
  \DataTypeTok{entry}\OperatorTok{:} \StringTok{'./src/index.js'}
\OperatorTok{\};}
\end{Highlighting}
\end{Shaded}

The \texttt{module.exports} line may confuse; it is covered in a later section on \emph{importing and exporting}\index{export} variables and functions.

\hypertarget{webpack-intro-npm-scripts}{%
\section{NPM scripts}\label{webpack-intro-npm-scripts}}

NPM scripts allow automating development tasks such as running unit tests, serving files, and more, we'll set it up to run webpack. The scripts are placed in the \texttt{package.json} file and are terminal commands.

By default \texttt{npm-init} creates the following \texttt{test} script, which echoes (prints) a message stating that no unit tests were set up.

\begin{Shaded}
\begin{Highlighting}[]
\ErrorTok{"scripts":} \FunctionTok{\{}
  \DataTypeTok{"test"}\FunctionTok{:} \StringTok{"echo }\CharTok{\textbackslash{}"}\StringTok{Error: no test specified}\CharTok{\textbackslash{}"}\StringTok{ && exit 1"}
\FunctionTok{\}}
\end{Highlighting}
\end{Shaded}

This script can be run from the terminal by typing \texttt{npm\ run\ test}. Those commands always follow the same pattern: \texttt{npm\ run} followed by the name of the script, in this case, \texttt{test}.

Adding the script to run webpack is very straightforward, we can add an entry called \texttt{build} that runs \texttt{webpack}.

\begin{Shaded}
\begin{Highlighting}[]
\ErrorTok{"scripts":} \FunctionTok{\{}
  \DataTypeTok{"test"}\FunctionTok{:} \StringTok{"echo }\CharTok{\textbackslash{}"}\StringTok{Error: no test specified}\CharTok{\textbackslash{}"}\StringTok{ && exit 1"}\FunctionTok{,}
  \DataTypeTok{"build"}\FunctionTok{:} \StringTok{"webpack"}
\FunctionTok{\}}
\end{Highlighting}
\end{Shaded}

So running \texttt{npm\ run\ build} produces the output file from the entry point file. However, we will modify this slightly in the next section as more features of webpack are uncovered.

\hypertarget{webpack-intro-webpack-mode}{%
\section{Source maps}\label{webpack-intro-webpack-mode}}

We will improve upon the previous section so we can run webpack on two different modes: one for production and one for development.

Since the output of webpack is any number of files bundled into one, it can make debugging more difficult. When files \texttt{a.js}, \texttt{b.js}, and \texttt{c.js} are bundled into \texttt{dist/main.js}, the stack trace will point to errors in \texttt{dist/main.js}, which is not helpful as the developer needs to know in which original file the bug lies.

Therefore, webpack comes with a ``development'' mode that allows including the ``source map,'' which maps the compiled code to the source files. This way, when an error or warning is raised JavaScript is able to point to the original line of code that causes it.

There are again many different ways to set this up in the configuration file as the source map can be placed in the bundled file itself, in another file, and more. However, the easiest way is probably to specify the mode using webpack's CLI tool. The source maps are optional as these make the output larger and one wants to keep this output as small as possible for it to load as fast as possible in web browsers\index{web browser}. Those will thus only be used while developing the project to trace back errors and warnings but will not be included in the final output for production.

Below we modify the scripts placed in the \texttt{package.json} file so two different scripts can be run: one for development and another for production.

\begin{Shaded}
\begin{Highlighting}[]
\ErrorTok{"scripts":} \FunctionTok{\{}
  \DataTypeTok{"test"}\FunctionTok{:} \StringTok{"echo }\CharTok{\textbackslash{}"}\StringTok{Error: no test specified}\CharTok{\textbackslash{}"}\StringTok{ && exit 1"}\FunctionTok{,}
  \DataTypeTok{"build-prod"}\FunctionTok{:} \StringTok{"webpack --mode=production"}\FunctionTok{,}
  \DataTypeTok{"build-dev"}\FunctionTok{:} \StringTok{"webpack --mode=development"}
\FunctionTok{\}}
\end{Highlighting}
\end{Shaded}

This allows running \texttt{npm\ run\ build-prod} to produce the production bundle and \texttt{npm\ run\ build-dev} to produce the development version that includes the source map.

\hypertarget{webpack-intro-bundle}{%
\section{Bundle}\label{webpack-intro-bundle}}

One can then bundle the code using the scripts that we defined to produce the output bundle. Since we have not specified any \texttt{output} in webpack's configuration file, it will create it at the default location \texttt{dist/main.js}.

\begin{Shaded}
\begin{Highlighting}[]
\ExtensionTok{npm}\NormalTok{ run build-prod}
\end{Highlighting}
\end{Shaded}

We can then include the output of webpack in the Shiny application to test that all works well.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(shiny)}

\NormalTok{mainJs <-}\StringTok{ }\NormalTok{htmltools}\OperatorTok{::}\KeywordTok{htmlDependency}\NormalTok{(}
  \DataTypeTok{name =} \StringTok{"main"}\NormalTok{,}
  \DataTypeTok{version =} \StringTok{"1.0.0"}\NormalTok{,}
  \DataTypeTok{src =} \StringTok{"./dist"}\NormalTok{,}
  \DataTypeTok{script =} \KeywordTok{c}\NormalTok{(}\DataTypeTok{file =} \StringTok{"main.js"}\NormalTok{)}
\NormalTok{)}

\NormalTok{ui <-}\StringTok{ }\KeywordTok{fluidPage}\NormalTok{(}
\NormalTok{  mainJs,}
  \KeywordTok{h1}\NormalTok{(}\StringTok{"A shiny app"}\NormalTok{)}
\NormalTok{)}

\NormalTok{server <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(...) \{\}}

\KeywordTok{shinyApp}\NormalTok{(ui, server)}
\end{Highlighting}
\end{Shaded}

Running the above launches the app, which presents the \texttt{alert()} that was placed in the \texttt{index.js} source file.

This makes for a great start but is not precisely interesting; in the following sections, we elaborate on this basic configuration to make better use of webpack's feature and produce something much more fun.

\hypertarget{webpack-intro-internal-dependencies}{%
\section{Internal Dependencies}\label{webpack-intro-internal-dependencies}}

Let's install a dependency\index{dependency} and use it in our Shiny application.

We'll install \href{https://github.com/ccampbell/mousetrap}{mousetrap,} a library to handle key-strokes. We're going to use it to hide the UI of the Shiny application behind a secret pass-phrase; it will only be revealed after it has been typed. This can be done by observing a specific set of key-strokes with mousetrap and set a Shiny input value when that particular sequence is typed.

\begin{rmdnote}
This is by no means a safe way to secure an application!
\end{rmdnote}

Though it is certainly not a real-world example, it is educational and quite a bit of fun.

The first thing to do is to install the mousetrap dependency; as indicated on the \href{https://github.com/ccampbell/mousetrap}{GitHub README} it can be obtained from NPM.

\begin{Shaded}
\begin{Highlighting}[]
\ExtensionTok{npm}\NormalTok{ install mousetrap --save}
\end{Highlighting}
\end{Shaded}

Note that we use \texttt{-\/-save} as mousetrap will need to be included in the output we create, it's not a library we import for development purposes.

\hypertarget{webpack-intro-external-dependencies}{%
\section{External Dependencies}\label{webpack-intro-external-dependencies}}

If dependencies with webpack have to be installed from NPM it begs the question; what about dependencies that are already included in the project and are not available on NPM.

For instance, this project is intended to work with a Shiny application, which comes bundled with \index{jQuery}, and the Shiny JavaScript library. First, the Shiny javaScript library is not available on NPM. Second installing it would result in duplicating dependencies, which is hardly best practice. Thankfully webpack comes with a simple mechanism to handle these cases; external dependencies\index{dependency} can be added to the configuration file under \texttt{externals}.

\begin{Shaded}
\begin{Highlighting}[]
\VariableTok{module}\NormalTok{.}\AttributeTok{exports} \OperatorTok{=} \OperatorTok{\{}
  \DataTypeTok{entry}\OperatorTok{:} \StringTok{'./src/index.js'}\OperatorTok{,}
  \DataTypeTok{externals}\OperatorTok{:} \OperatorTok{\{}
    \DataTypeTok{shiny}\OperatorTok{:} \StringTok{'Shiny'}
  \OperatorTok{\}}
\OperatorTok{\};}
\end{Highlighting}
\end{Shaded}

The above will allow importing the \texttt{Shiny} object in scripts, which is needed to set the input value with \texttt{Shiny.setInputValue}; hence \texttt{Shiny} must be accessible in webpack. Let us delve into the import/export mechanism.

\hypertarget{webpack-intro-import-export}{%
\section{Import and Export}\label{webpack-intro-import-export}}

To demonstrate how webpack enables modularising code, we will not place all the code in the \texttt{index.js} file. We create two other files: \texttt{secret.js} and \texttt{input.js}. The first will contain the pass-phrase and the second will have the code to handle the key strokes via mousetrap and set the Shiny input. This will enable using the pass-phrase in multiple places without duplicating code.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{file.create}\NormalTok{(}\StringTok{"src/input.js"}\NormalTok{)}
\KeywordTok{file.create}\NormalTok{(}\StringTok{"src/secret.js"}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

Therefore, as shown in Figure \ref{fig:webpack-shiny}, the entry point \texttt{index.js} needs to import the \texttt{input.js} file, which itself imports the pass-phrase from \texttt{secret.js}.

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/07-webpack-shiny} 

}

\caption{Webpack with Shiny}\label{fig:webpack-shiny}
\end{figure}

Again, there are multiple ways to import and export\index{export} modules, functions, variables, etc. This book will use the ES6 syntax as \href{https://webpack.js.org/api/module-methods/\#es6-recommended}{recommended by webpack.} Though this mechanism is present in other languages, such as Python (where it somewhat resembles ES6), it will take some getting used to for R programmers as though this language features some form of import (\texttt{library()}) and export\index{export} (\texttt{@export} roxygen2 tag), this differs significantly from how it works in webpack. This is, however, key to using webpack, as it is what ultimately enables the creation of modules that make code more robust.

There are two different kinds of exports and imports possible, ``named'' and ``default.'' We shall cover them in that order.

\hypertarget{webpack-intro-import-export-named}{%
\subsection{Named}\label{webpack-intro-import-export-named}}

Let's place the variable \texttt{secret} in the \texttt{secret.js} file. As a reminder, this variable will have to be imported by in another file (\texttt{input.js}) where it will be used to check if the pass-phrase typed by the user is correct.

Declaring the variable itself does not change, we use the keyword \texttt{let} to declare a variable named \texttt{secret} that holds the pass-phrase. The issue is that with webpack, this variable will be internal to the file where it is declared. However, we ultimately want to import that variable in another file. To do so, we can place the keyword \texttt{export} in front of the declaration to indicate that this variable is exported from the file. Note that this will also work with functions and classes, and other objects.

Placing \texttt{export} in front of an object constitutes a \emph{named export}; the \texttt{secret.js} file explicitly exports\index{export} the variable named \texttt{secret}.

\begin{Shaded}
\begin{Highlighting}[]
\ImportTok{export} \KeywordTok{let}\NormalTok{ secret }\OperatorTok{=} \StringTok{'s e c r e t'}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

Then this variable can be imported in the \texttt{input.js} file. The named export in \texttt{secret.js} comes with a corresponding named import in \texttt{input.js} to import the variable named \texttt{secret}; this is indicated by the curly braces. Note that again we include the path to the file (\texttt{./secret.js}), importing from \texttt{secret.js} without the path will fail.

\begin{Shaded}
\begin{Highlighting}[]
\ImportTok{import} \OperatorTok{\{}\NormalTok{ secret }\OperatorTok{\}} \ImportTok{from} \StringTok{'./secret.js'}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

The curly braces are used for named imports as multiple such variables or functions can then be imported, e.g., \texttt{import\ \{\ foo,\ bar\ \}\ from\ \textquotesingle{}./file.js\textquotesingle{};} to import the named exports \texttt{foo} and \texttt{bar} from \texttt{file.js}.

\hypertarget{webpack-intro-import-export-default}{%
\subsection{Default}\label{webpack-intro-import-export-default}}

An alternative would be to use a default export. A file can have a default export; said default could be a variable, a function, a list, or any number of things but \emph{there can only be a single default export per file}.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{// declare}
\KeywordTok{let}\NormalTok{ secret }\OperatorTok{=} \StringTok{'s e c r e t'}\OperatorTok{;}

\CommentTok{// export}
\ImportTok{export} \ImportTok{default}\NormalTok{ secret}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

Rather interestingly, because multiple variables can be declared on a single line (e.g., \texttt{var\ a,b,c;}) but only a single default can exist, the default export\index{export} and vriable declaration cannot be placed on a single line.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{// invalid}
\ImportTok{export} \ImportTok{default}\NormalTok{ secret }\OperatorTok{=} \StringTok{'s e c r e t'}\OperatorTok{;}

\CommentTok{// valid}
\KeywordTok{var}\NormalTok{ x }\OperatorTok{=} \DecValTok{0}\OperatorTok{,}
\NormalTok{    y }\OperatorTok{=} \KeywordTok{true}\OperatorTok{;}

\ImportTok{export} \ImportTok{default} \OperatorTok{\{}\NormalTok{x}\OperatorTok{,}\NormalTok{ y}\OperatorTok{\}}
\end{Highlighting}
\end{Shaded}

This only applies to variables as only a single function can be declared by line so declaring a function and its default export on athe same line is valid.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{// valid}
\ImportTok{export} \ImportTok{default} \KeywordTok{function} \AttributeTok{sayHello}\NormalTok{() }\OperatorTok{\{}
  \AttributeTok{alert}\NormalTok{(}\StringTok{"Hello!"}\NormalTok{)}
\OperatorTok{\};}
\end{Highlighting}
\end{Shaded}

Importing default exports in other files resembles all too much the syntax of named imports, which may lead to confusion: it's essentially the same omitting the curly braces.

\begin{Shaded}
\begin{Highlighting}[]
\ImportTok{import}\NormalTok{ secret }\ImportTok{from} \StringTok{'./secret.js'}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

\hypertarget{webpack-intro-import-export-wrap-up}{%
\subsection{Wrap-up}\label{webpack-intro-import-export-wrap-up}}

We'll be using a named export method in \texttt{secret.js}. The same general logic can be applied to import the external dependency Shiny as well as mousetrap.

\begin{Shaded}
\begin{Highlighting}[]
\ImportTok{import}\NormalTok{ Shiny }\ImportTok{from} \StringTok{'shiny'}\OperatorTok{;}
\ImportTok{import} \OperatorTok{\{}\NormalTok{ secret }\OperatorTok{\}} \ImportTok{from} \StringTok{'./secret.js'}\OperatorTok{;}
\ImportTok{import}\NormalTok{ Mousetrap }\ImportTok{from} \StringTok{'mousetrap'}\OperatorTok{;}

\VariableTok{Mousetrap}\NormalTok{.}\AttributeTok{bind}\NormalTok{(secret}\OperatorTok{,} \KeywordTok{function}\NormalTok{() }\OperatorTok{\{} 
  \VariableTok{Shiny}\NormalTok{.}\AttributeTok{setInputValue}\NormalTok{(}\StringTok{'secret'}\OperatorTok{,} \KeywordTok{true}\NormalTok{)}\OperatorTok{;}
\OperatorTok{\}}\NormalTok{)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

Finally, remember to import \texttt{input.js} in the entry point \texttt{index.js}.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{// index.js}
\ImportTok{import} \StringTok{'./input.js'}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

This can then be bundled with \texttt{npm\ run\ bundle-prod}, which will start at the entry point (\texttt{index.js}) observe that it imports the file \texttt{input.js}, then look at that file and see that it imports \texttt{secret.js}; webpack builds this dependency tree and includes all that is needed in the bundle.

This can be used in the Shiny application, which we modify so it listens to the \texttt{secret} input and only when that input is set renders a plot and a message.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(shiny)}

\NormalTok{mainJs <-}\StringTok{ }\NormalTok{htmltools}\OperatorTok{::}\KeywordTok{htmlDependency}\NormalTok{(}
  \DataTypeTok{name =} \StringTok{"main"}\NormalTok{,}
  \DataTypeTok{version =} \StringTok{"1.0.0"}\NormalTok{,}
  \DataTypeTok{src =} \StringTok{"./dist"}\NormalTok{,}
  \DataTypeTok{script =} \KeywordTok{c}\NormalTok{(}\DataTypeTok{file =} \StringTok{"main.js"}\NormalTok{)}
\NormalTok{)}

\NormalTok{ui <-}\StringTok{ }\KeywordTok{fluidPage}\NormalTok{(}
\NormalTok{  mainJs,}
  \KeywordTok{p}\NormalTok{(}\StringTok{"Type the secret phrase"}\NormalTok{),}
  \KeywordTok{uiOutput}\NormalTok{(}\StringTok{"hello"}\NormalTok{),}
  \KeywordTok{plotOutput}\NormalTok{(}\StringTok{"plot"}\NormalTok{)}
\NormalTok{)}

\NormalTok{server <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(input, output) \{}
\NormalTok{  output}\OperatorTok{$}\NormalTok{hello <-}\StringTok{ }\KeywordTok{renderUI}\NormalTok{(\{}
    \KeywordTok{req}\NormalTok{(input}\OperatorTok{$}\NormalTok{secret)}
    \KeywordTok{h2}\NormalTok{(}\StringTok{"You got the secret right!"}\NormalTok{)}
\NormalTok{  \})}

\NormalTok{  output}\OperatorTok{$}\NormalTok{plot <-}\StringTok{ }\KeywordTok{renderPlot}\NormalTok{(\{}
    \KeywordTok{req}\NormalTok{(input}\OperatorTok{$}\NormalTok{secret)}
    \KeywordTok{hist}\NormalTok{(cars}\OperatorTok{$}\NormalTok{speed)}
\NormalTok{  \})}
\NormalTok{\}}

\KeywordTok{shinyApp}\NormalTok{(ui, server)}
\end{Highlighting}
\end{Shaded}

Once the application is launched the user can type the phrase \texttt{secret} to see the content of the application (see Figure \ref{fig:mousetrap}).

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/mousetrap} 

}

\caption{Mousetrap example}\label{fig:mousetrap}
\end{figure}

That is it for this chapter. As stated multiple times there is far more depth to webpack, but this is outside the scope of this book, instead in the next chapter we discover an easier way to set up such projects and make R and webpack work in a more seamless fashion.

\hypertarget{packer-overview}{%
\chapter{Webpack with R}\label{packer-overview}}

In the previous chapter, we put together a simple Shiny application using NPM and webpack. Hopefully, it hinted at some of the powerful things webpack can do but also revealed a downside: the overhead in merely creating the project. Moreover, the configuration will change depending on what the project is (application, package, etc.).

In this chapter, we discover the \href{https://github.com/JohnCoene/packer}{packer} \citep{R-packer} R package, which provides many convenience functions to create and manage R projects that make use of webpack and NPM.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{install.packages}\NormalTok{(}\StringTok{"packer"}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

\hypertarget{packer-principles}{%
\section{Principles of packer}\label{packer-principles}}

There are a few principles that the packer package follows strictly.

\begin{enumerate}
\def\labelenumi{\arabic{enumi}.}
\tightlist
\item
  It only aspires to become a specialised usethis for working with JavaScript and R. As such, it takes inspiration from other packages such as htmlwidgets and devtools.
\item
  It will never become a dependency\index{dependency} to what you create. It's in a sense very much like an NPM ``developer'' dependency; it's used to develop the project but does not bring any additional overhead to what you're building.
\item
  It should not interfere with the mission of webpack to build more robust JavaScript code. Therefore, packer only builds on top of already, strict R structures, namely packages (where golem can be used to create Shiny applications).
\end{enumerate}

\hypertarget{packer-scaffolds}{%
\section{Scaffolds}\label{packer-scaffolds}}

Packer is comprised of surprisingly few functions; the most important ones are in the \texttt{scaffold} family. The term scaffold was borrowed from the htmlwidgets package, which features the function \texttt{scaffoldWidget} (already used in this book). The idea of scaffolds in packer is very similar to the \texttt{scaffoldWidget} function: they set up the basic structure for projects.

Whilst htmlwidgets only allows creating scaffolds\index{scaffold} for widgets; packer allows creating scaffolds for several things, namely:

\begin{itemize}
\tightlist
\item
  Widgets with \texttt{scaffold\_widget}
\item
  Shiny inputs with \texttt{scaffold\_input}
\item
  Shiny outputs with \texttt{scaffold\_output}
\item
  Shiny extensions with \texttt{scaffold\_extension}
\item
  Golem applications with \texttt{scaffold\_golem}
\end{itemize}

This gives a few powerful functions that correctly set up webpack. These will build the necessary file structure and configuration depending on the scaffold and the context (whether it is a basic package, a golem application, a package with an existing scaffold, etc.)

\begin{rmdnote}
One can use multiple scaffolds in a single package or Shiny application.
\end{rmdnote}

Packer goes beyond merely setting up webpack and NPM; it will also create the necessary R functions, roxygen documentation, and examples, so every scaffold is fully functional out-of-the-box.

With some variations that will be explored in the coming sections, packer's \texttt{scaffold} functions generally do the following:

\begin{itemize}
\tightlist
\item
  Initialise npm with \texttt{npm\ init} and prefills the \texttt{package.json} file
\item
  Install webpack and its CLI with \texttt{npm\ install\ webpack\ webpack-cli\ -\/-save-dev}
\item
  Creates three webpack configuration files: \texttt{webpack.common.js}, \texttt{webpack.prod.js}, and \texttt{webpack.dev.js}
\item
  Creates the \texttt{srcjs} directory for the JavaScript source code
\item
  Creates raw JavaScript files within the \texttt{srcjs} directory, e.g.: \texttt{index.js}
\item
  Creates the R functions (if necessary)
\item
  Adds the necessary NPM scripts to \texttt{package.json}
\item
  Adds all relevant files to the \texttt{.Rbuildignore} and \texttt{.gitignore} files
\item
  Adds relevant dependencies to the \texttt{DESCRIPTION}, e.g.: \texttt{shiny} when scaffolding an input
\item
  Finally, it (optionally) opens interesting files to develop the project in the IDE
\end{itemize}

In the following sections, we unpack some of this as we explore a specific scaffold.

\hypertarget{packer-inputs}{%
\section{Inputs}\label{packer-inputs}}

In a previous chapter, we explored how to build custom Shiny inputs. Here, we'll use the packer package to produce a Shiny button that increments at every click; hence we create a package called ``increment.''

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{usethis}\OperatorTok{::}\KeywordTok{create_package}\NormalTok{(}\StringTok{"increment"}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

From the root of the package, we scaffold a custom input. Notably, this takes a \texttt{name} argument, which is used as names for the various files, functions, and modules it creates so choose it with care. The function prints some information about the operations it executes.

When run from an interactive session, packer also opens the most pertinent files in the default editor or IDE.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{packer}\OperatorTok{::}\KeywordTok{scaffold_input}\NormalTok{(}\StringTok{"increment"}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{── }\ExtensionTok{Scaffolding}\NormalTok{ shiny input ──────────────────────────────────────── increment ── }
\NormalTok{✔ }\ExtensionTok{Initialiased}\NormalTok{ npm}
\NormalTok{✔ }\ExtensionTok{Created}\NormalTok{ srcjs/inputs directory}
\NormalTok{✔ }\ExtensionTok{Created}\NormalTok{ inst/packer directory}
\NormalTok{✔ }\ExtensionTok{webpack}\NormalTok{, webpack-cli, webpack-merge installed with scope dev}
\NormalTok{✔ }\ExtensionTok{Created}\NormalTok{ srcjs/config directory}
\NormalTok{✔ }\ExtensionTok{Created}\NormalTok{ webpack config files}
\NormalTok{✔ }\ExtensionTok{Created} \StringTok{'input'}\NormalTok{ module}
\NormalTok{✔ }\ExtensionTok{Created}\NormalTok{ srcjs/index.js}
\NormalTok{✔ }\ExtensionTok{Created}\NormalTok{ R file and function}
\NormalTok{✔ }\ExtensionTok{Added}\NormalTok{ npm scripts}

\NormalTok{── }\ExtensionTok{Adding}\NormalTok{ files to }\StringTok{'.gitignore'}\NormalTok{ and }\StringTok{'.Rbuildignore'}\NormalTok{ ──}

\NormalTok{✔ }\ExtensionTok{Setting}\NormalTok{ active project to }\StringTok{'/javascript-for-r/code/increment'}
\NormalTok{✔ }\ExtensionTok{Adding} \StringTok{'^srcjs$'}\NormalTok{ to }\StringTok{'.Rbuildignore'}
\NormalTok{✔ }\ExtensionTok{Adding} \StringTok{'^node_modules$'}\NormalTok{ to }\StringTok{'.Rbuildignore'}
\NormalTok{✔ }\ExtensionTok{Adding} \StringTok{'^package\textbackslash{}\textbackslash{}.json$'}\NormalTok{ to }\StringTok{'.Rbuildignore'}
\NormalTok{✔ }\ExtensionTok{Adding} \StringTok{'^package-lock\textbackslash{}\textbackslash{}.json$'}\NormalTok{ to }\StringTok{'.Rbuildignore'}
\NormalTok{✔ }\ExtensionTok{Adding} \StringTok{'^webpack\textbackslash{}\textbackslash{}.dev\textbackslash{}\textbackslash{}.js$'}\NormalTok{ to }\StringTok{'.Rbuildignore'}
\NormalTok{✔ }\ExtensionTok{Adding} \StringTok{'^webpack\textbackslash{}\textbackslash{}.prod\textbackslash{}\textbackslash{}.js$'}\NormalTok{ to }\StringTok{'.Rbuildignore'}
\NormalTok{✔ }\ExtensionTok{Adding} \StringTok{'^webpack\textbackslash{}\textbackslash{}.common\textbackslash{}\textbackslash{}.js$'}\NormalTok{ to }\StringTok{'.Rbuildignore'}
\NormalTok{✔ }\ExtensionTok{Adding} \StringTok{'node_modules'}\NormalTok{ to }\StringTok{'.gitignore'}

\NormalTok{── }\ExtensionTok{Adding}\NormalTok{ packages to Imports ──}

\NormalTok{✔ }\ExtensionTok{Adding} \StringTok{'shiny'}\NormalTok{ to Imports field in DESCRIPTION}
\NormalTok{● }\ExtensionTok{Refer}\NormalTok{ to functions with }\KeywordTok{`}\FunctionTok{shiny::fun()}\KeywordTok{`}
\NormalTok{✔ }\ExtensionTok{Adding} \StringTok{'htmltools'}\NormalTok{ to Imports field in DESCRIPTION}
\NormalTok{● }\ExtensionTok{Refer}\NormalTok{ to functions with }\KeywordTok{`}\FunctionTok{htmltools::fun()}\KeywordTok{`}

\NormalTok{── }\ExtensionTok{Scaffold}\NormalTok{ built ──}

\NormalTok{ℹ }\ExtensionTok{Run} \KeywordTok{`}\ExtensionTok{bundle}\KeywordTok{`}\NormalTok{ to build the JavaScript files}
\end{Highlighting}
\end{Shaded}

The scaffold\index{scaffold} creates the file structure below. Notice that \texttt{increment} was used as the name of some files and that packer creates three webpack configuration files; one for development, another for production, and a third that contains configuration shared across those two modes.

It created one R file, \texttt{increment.R}, which contains the exported\index{export} input function named \texttt{incrementInput}. It also created the \texttt{inst/packer} directory, which is currently empty but will eventually contain the bundled JavaScript file(s).

The function also initialised NPM, which created the \texttt{node\_modules} directory, as well as the \texttt{package.json} and \texttt{package-lock.json}, packer also added the necessary scripts to \texttt{package.json} so one should not need to interact with those files directly.

Finally, it also created the \texttt{srcjs} directory containing core JavaScript files to produce the input binding.

\begin{verbatim}
.
├── DESCRIPTION
├── NAMESPACE
├── R
│   ├── increment.R
├── inst
│   └── packer
├── node_modules
│   └── ...
├── package.json
├── srcjs
│   ├── config
│   ├── inputs
│   └── index.js
├── webpack.common.js
├── webpack.dev.js
└── webpack.prod.js
\end{verbatim}

In the following sections, we break down those files to better understand what packer scaffolded and how to use it.

\hypertarget{packer-r-file}{%
\section{R file}\label{packer-r-file}}

The R file contains the \texttt{incrementInput} function. Notably, the function contains the necessary dependency\index{dependency}, although it currently looks for a file that is yet created (we'll bundle the JavaScript later). Also, of importance is the class attribute set for the input: \texttt{incrementBinding}. As you might remember, this class will be referenced in the JavaScript binding's \texttt{find} method.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{incrementInput <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(inputId, }\DataTypeTok{value =} \DecValTok{0}\NormalTok{)\{}

  \KeywordTok{stopifnot}\NormalTok{(}\OperatorTok{!}\KeywordTok{missing}\NormalTok{(inputId))}
  \KeywordTok{stopifnot}\NormalTok{(}\KeywordTok{is.numeric}\NormalTok{(value))}

\NormalTok{  dep <-}\StringTok{ }\NormalTok{htmltools}\OperatorTok{::}\KeywordTok{htmlDependency}\NormalTok{(}
    \DataTypeTok{name =} \StringTok{"incrementBinding"}\NormalTok{,}
    \DataTypeTok{version =} \StringTok{"1.0.0"}\NormalTok{,}
    \DataTypeTok{src =} \KeywordTok{c}\NormalTok{(}\DataTypeTok{file =} \KeywordTok{system.file}\NormalTok{(}\StringTok{"packer"}\NormalTok{, }\DataTypeTok{package =} \StringTok{"increment"}\NormalTok{)),}
    \DataTypeTok{script =} \StringTok{"increment.js"}
\NormalTok{  )}

  \KeywordTok{tagList}\NormalTok{(}
\NormalTok{    dep,}
\NormalTok{    tags}\OperatorTok{$}\KeywordTok{button}\NormalTok{(}
      \DataTypeTok{id =}\NormalTok{ inputId,}
      \DataTypeTok{class =} \StringTok{"incrementBinding btn btn-default"}\NormalTok{,}
      \DataTypeTok{type =} \StringTok{"button"}\NormalTok{,}
\NormalTok{      value}
\NormalTok{    )}
\NormalTok{  )}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

Note that packer does not use the namespace of functions (e.g., \texttt{shiny::tagList}). Instead, it uses the roxygen2 tags to import the necessary functions: \texttt{@importFrom\ Shiny\ tags\ tagList}. Rather nicely, packer also created an example in the roxygen documentation. We'll run this later after we've bundled the JavaScript.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{#' @examples }
\CommentTok{#' library(shiny)}
\CommentTok{#' }
\CommentTok{#' ui <- fluidPage(}
\CommentTok{#'  incrementInput("theId", 0)}
\CommentTok{#' )}
\CommentTok{#' }
\CommentTok{#' server <- function(input, output)\{}
\CommentTok{#' }
\CommentTok{#'  observeEvent(input$theId, \{}
\CommentTok{#'    print(input$theId)}
\CommentTok{#'  \})}
\CommentTok{#' }
\CommentTok{#' \}}
\CommentTok{#' }
\CommentTok{#' if(interactive())}
\CommentTok{#'  shinyApp(ui, server)}
\end{Highlighting}
\end{Shaded}

\hypertarget{packer-js-files}{%
\section{JavaScript Files}\label{packer-js-files}}

In the \texttt{srcjs/inputs} directory, packer created \texttt{increment.js}. This code contains the JavaScript binding for the increment button. As a reminder, one is not limited to a single scaffold. We could scaffold another input, the JavaScript binding of which would be placed alongside this file, also in \texttt{srcjs/inputs}.

\begin{Shaded}
\begin{Highlighting}[]
\ImportTok{import}\NormalTok{ $ }\ImportTok{from} \StringTok{'jquery'}\OperatorTok{;}
\ImportTok{import} \StringTok{'shiny'}\OperatorTok{;}

\AttributeTok{$}\NormalTok{(document).}\AttributeTok{on}\NormalTok{(}\StringTok{"click"}\OperatorTok{,} \StringTok{"button.incrementBinding"}\OperatorTok{,} 
  \KeywordTok{function}\NormalTok{(evt) }\OperatorTok{\{}
    \CommentTok{// evt.target is the button that was clicked}
    \KeywordTok{var}\NormalTok{ el }\OperatorTok{=} \AttributeTok{$}\NormalTok{(}\VariableTok{evt}\NormalTok{.}\AttributeTok{target}\NormalTok{)}\OperatorTok{;}

    \CommentTok{// Set the button's text to its current value plus 1}
    \VariableTok{el}\NormalTok{.}\AttributeTok{text}\NormalTok{(}\AttributeTok{parseInt}\NormalTok{(}\VariableTok{el}\NormalTok{.}\AttributeTok{text}\NormalTok{()) }\OperatorTok{+} \DecValTok{1}\NormalTok{)}\OperatorTok{;}

    \CommentTok{// Raise an event to signal that the value changed}
    \VariableTok{el}\NormalTok{.}\AttributeTok{trigger}\NormalTok{(}\StringTok{"change"}\NormalTok{)}\OperatorTok{;}
  \OperatorTok{\}}
\NormalTok{)}\OperatorTok{;}

\KeywordTok{var}\NormalTok{ incrementBinding }\OperatorTok{=} \KeywordTok{new} \VariableTok{Shiny}\NormalTok{.}\AttributeTok{InputBinding}\NormalTok{()}\OperatorTok{;}

\VariableTok{$}\NormalTok{.}\AttributeTok{extend}\NormalTok{(incrementBinding}\OperatorTok{,} \OperatorTok{\{}
  \DataTypeTok{find}\OperatorTok{:} \KeywordTok{function}\NormalTok{(scope) }\OperatorTok{\{}
    \ControlFlowTok{return} \AttributeTok{$}\NormalTok{(scope).}\AttributeTok{find}\NormalTok{(}\StringTok{".incrementBinding"}\NormalTok{)}\OperatorTok{;}
  \OperatorTok{\},}
  \DataTypeTok{getValue}\OperatorTok{:} \KeywordTok{function}\NormalTok{(el) }\OperatorTok{\{}
    \ControlFlowTok{return} \AttributeTok{parseInt}\NormalTok{(}\AttributeTok{$}\NormalTok{(el).}\AttributeTok{text}\NormalTok{())}\OperatorTok{;}
  \OperatorTok{\},}
  \DataTypeTok{setValue}\OperatorTok{:} \KeywordTok{function}\NormalTok{(el}\OperatorTok{,}\NormalTok{ value) }\OperatorTok{\{}
    \AttributeTok{$}\NormalTok{(el).}\AttributeTok{text}\NormalTok{(value)}\OperatorTok{;}
  \OperatorTok{\},}
  \DataTypeTok{subscribe}\OperatorTok{:} \KeywordTok{function}\NormalTok{(el}\OperatorTok{,}\NormalTok{ callback) }\OperatorTok{\{}
    \AttributeTok{$}\NormalTok{(el).}\AttributeTok{on}\NormalTok{(}\StringTok{"change.incrementBinding"}\OperatorTok{,} \KeywordTok{function}\NormalTok{(e) }\OperatorTok{\{}
      \AttributeTok{callback}\NormalTok{()}\OperatorTok{;}
    \OperatorTok{\}}\NormalTok{)}\OperatorTok{;}
  \OperatorTok{\},}
  \DataTypeTok{unsubscribe}\OperatorTok{:} \KeywordTok{function}\NormalTok{(el) }\OperatorTok{\{}
    \AttributeTok{$}\NormalTok{(el).}\AttributeTok{off}\NormalTok{(}\StringTok{".incrementBinding"}\NormalTok{)}\OperatorTok{;}
  \OperatorTok{\}}
\OperatorTok{\}}\NormalTok{)}\OperatorTok{;}

\VariableTok{Shiny}\NormalTok{.}\VariableTok{inputBindings}\NormalTok{.}\AttributeTok{register}\NormalTok{(}
\NormalTok{  incrementBinding}\OperatorTok{,} \StringTok{"increment.incrementBinding"}
\NormalTok{)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

The \texttt{srcjs/index.js} file was also created; it imports the JavaScript binding detailed above with \texttt{import\ \textquotesingle{}./inputs/increment.js\textquotesingle{};}. Notably, by default, packer does not bundle all of these files into one; \texttt{index.js} is only populated for convenience in the event one would want to change this behaviour. Instead, packer uses \texttt{srcjs/inputs/increment.js} as an entry point. It will handle multiple entry points, so every input, output, widgets, etc. are bundled separately. This is done so one can import those dynamically.

\hypertarget{packer-bundle}{%
\section{Bundle}\label{packer-bundle}}

You can then run \texttt{packer::bundle} to bundle the JavaScript. The entry points and output directories will depend on the scaffold, Shiny inputs' bundles are placed in the \texttt{inst/packer} directory unless this was run from a golem application, in which case the output is automatically changed to golem's standard.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{packer}\OperatorTok{::}\KeywordTok{bundle}\NormalTok{()}
\end{Highlighting}
\end{Shaded}

By default packer will bundle the files for production, this can be managed with the functions \texttt{packer::bundle\_dev()} and \texttt{packer::bundle\_prod()}.

Once the JavaScript is bundled, we can install or load the package with \texttt{devtools::load\_all} and use the example that was created for us to test the input.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{library}\NormalTok{(shiny)}

\NormalTok{ui <-}\StringTok{ }\KeywordTok{fluidPage}\NormalTok{(}
  \KeywordTok{incrementInput}\NormalTok{(}\StringTok{"theId"}\NormalTok{, }\DecValTok{0}\NormalTok{)}
\NormalTok{)}

\NormalTok{server <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(input, output)\{}

  \KeywordTok{observeEvent}\NormalTok{(input}\OperatorTok{$}\NormalTok{theId, \{}
    \KeywordTok{print}\NormalTok{(input}\OperatorTok{$}\NormalTok{theId)}
\NormalTok{  \})}

\NormalTok{\}}

\ControlFlowTok{if}\NormalTok{(}\KeywordTok{interactive}\NormalTok{())}
  \KeywordTok{shinyApp}\NormalTok{(ui, server)}
\end{Highlighting}
\end{Shaded}

No code was written, yet we have a fully-functional input! We'll leave ir at this: it's not only meant to create increment buttons, but this sets up a solid base for the developer to customise the code and conveniently create a different input.

It is worth noting that we built a Shiny input from within a package, this is meant to be exported\index{export} and used in Shiny applications elsewhere, but were one to run these same steps from a golem application packer would adapt the output path so that the input can be used directly in the application.

\hypertarget{packer-adv}{%
\chapter{Webpack Advanced}\label{packer-adv}}

We're about to cover slightly more advanced uses of NPM and webpack with R using packer. These involve using an NPM dependency to develop a widget and use \href{https://vuejs.org/}{Vue.js}\index{Vue} and Bootstrap 4 to power the front end of a Shiny application.

Those will make for more concrete cases to bring webpack into your workflow, and also enable explaining more advanced topics only thus far briefly touched upon, such as transpiling.

\hypertarget{packer-adv-widgets}{%
\section{Widgets}\label{packer-adv-widgets}}

The widget scaffold\index{scaffold}, like all other scaffolds, must be run from within the root of a package. To demonstrate we'll write a widget for the \href{https://github.com/inorganik/countUp.js/}{countup} library that allows animating numbers.

First, we create a package which we name \texttt{counter}. You can name the package differently but avoid naming it \texttt{countup}. We will later have to install the external dependency\index{dependency} also named \texttt{countup} and NPM does not allow a project named X to use a dependency also named X.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{usethis}\OperatorTok{::}\KeywordTok{create_package}\NormalTok{(}\StringTok{"counter"}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

From the root of the package, we scaffold the widget with \texttt{scaffold\_widget}, which prints out some information on what packer exactly does.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{packer}\OperatorTok{::}\KeywordTok{scaffold_widget}\NormalTok{(}\StringTok{"countup"}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

\begin{verbatim}
── Scaffolding widget ──────────────────────────────── countup ── 
✔ Bare widget setup
✔ Created srcjs directory
✔ Initialiased npm
✔ webpack, webpack-cli, webpack-merge installed with scope dev
✔ Created srcjs/config directory
✔ Created webpack config files
✔ Created srcjs/modules directory
✔ Created srcjs/widgets directory
✔ Created srcjs/index.js
✔ Moved bare widget to srcjs
✔ Added npm scripts

── Adding files to '.gitignore' and '.Rbuildignore' ──

✔ Setting active project to '/Projects/countup'
✔ Adding '^srcjs$' to '.Rbuildignore'
✔ Adding '^node_modules$' to '.Rbuildignore'
✔ Adding '^package\\.json$' to '.Rbuildignore'
✔ Adding '^package-lock\\.json$' to '.Rbuildignore'
✔ Adding '^webpack\\.dev\\.js$' to '.Rbuildignore'
✔ Adding '^webpack\\.prod\\.js$' to '.Rbuildignore'
✔ Adding '^webpack\\.common\\.js$' to '.Rbuildignore'
✔ Adding 'node_modules' to '.gitignore'

── Adding packages to Imports ──

✔ Adding 'htmlwidgets' to Imports field in DESCRIPTION
● Refer to functions with `htmlwidgets::fun()`

── Scaffold built ──

ℹ Run `bundle` to build the JavaScript files
\end{verbatim}

Importantly, it runs \texttt{htmlwidgets::scaffoldWidget} internally, there is thus no need to run this function. About the widget itself, there is very little difference between what \texttt{htmlwidgets::scaffoldWidget} and \texttt{packer::scaffold\_widget}. While, if you remember, the initial scaffold\index{scaffold} of htmlwidgets includes a simple function to display a message in HTML using \texttt{innerText}. The scaffold produced by packer differs only in that this message is displayed in \texttt{\textless{}h1\textgreater{}} HTML\index{HTML} tags. That is so it can, from the get-go, demonstrate how to modularise a widget. We'll cover that in just a minute, before we do so, bundle the JavaScript and run the \texttt{counter} function to observe the output it generates.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{packer}\OperatorTok{::}\KeywordTok{bundle}\NormalTok{()}
\NormalTok{devtools}\OperatorTok{::}\KeywordTok{load_all}\NormalTok{()}
\KeywordTok{countup}\NormalTok{(}\StringTok{"Hello widgets!"}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

This indeed displays the message in \texttt{\textless{}h1\textgreater{}} HTML tags, now onto unpacking the structure generated by packer. We'll skip the R code to keep this concise as nothing differs from a standard widget on that side. Instead, we'll focus on the JavaScript code in the \texttt{srcjs} directory. First, in the \texttt{srcjs/widgets} directory, one will find the file \texttt{countup.js}. This file contains the code that produces the widget.

At the top of the file are the imports. First, it imports \texttt{widgets}, which is the htmlwidgets \emph{external dependency,} second it imports the function \texttt{asHeader} from the \texttt{header.js} file in the \texttt{modules} directory.

\begin{Shaded}
\begin{Highlighting}[]
\ImportTok{import} \StringTok{'widgets'}\OperatorTok{;}
\ImportTok{import} \OperatorTok{\{}\NormalTok{ asHeader }\OperatorTok{\}} \ImportTok{from} \StringTok{'../modules/header.js'}\OperatorTok{;} 

\VariableTok{HTMLWidgets}\NormalTok{.}\AttributeTok{widget}\NormalTok{(}\OperatorTok{\{}

  \DataTypeTok{name}\OperatorTok{:} \StringTok{'countup'}\OperatorTok{,}

  \DataTypeTok{type}\OperatorTok{:} \StringTok{'output'}\OperatorTok{,}

  \DataTypeTok{factory}\OperatorTok{:} \KeywordTok{function}\NormalTok{(el}\OperatorTok{,}\NormalTok{ width}\OperatorTok{,}\NormalTok{ height) }\OperatorTok{\{}

    \CommentTok{// }\AlertTok{TODO}\CommentTok{: define shared variables for this instance}

    \ControlFlowTok{return} \OperatorTok{\{}

      \DataTypeTok{renderValue}\OperatorTok{:} \KeywordTok{function}\NormalTok{(x) }\OperatorTok{\{}

        \CommentTok{// }\AlertTok{TODO}\CommentTok{: code to render the widget, e.g.}
        \VariableTok{el}\NormalTok{.}\AttributeTok{innerHTML} \OperatorTok{=} \AttributeTok{asHeader}\NormalTok{(x)}\OperatorTok{;}

      \OperatorTok{\},}

      \DataTypeTok{resize}\OperatorTok{:} \KeywordTok{function}\NormalTok{(width}\OperatorTok{,}\NormalTok{ height) }\OperatorTok{\{}

        \CommentTok{// }\AlertTok{TODO}\CommentTok{: code to re-render the widget with a new size}

      \OperatorTok{\}}

    \OperatorTok{\};}
  \OperatorTok{\}}
\OperatorTok{\}}\NormalTok{)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

The \texttt{header.js} file includes the \texttt{asHeader} function, which accepts an \texttt{x} argument that is used to create the \texttt{\textless{}h1\textgreater{}} message. This function is exported\index{export}.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{const}\NormalTok{ asHeader }\OperatorTok{=}\NormalTok{ (x) }\KeywordTok{=>} \OperatorTok{\{}
  \ControlFlowTok{return} \StringTok{'<h1>'} \OperatorTok{+} \VariableTok{x}\NormalTok{.}\AttributeTok{message} \OperatorTok{+} \StringTok{'</h1>'}\OperatorTok{;}
\OperatorTok{\}}

\ImportTok{export} \OperatorTok{\{}\NormalTok{ asHeader }\OperatorTok{\};}
\end{Highlighting}
\end{Shaded}

We will make changes to the JavaScript so that instead of displaying the message as text, it uses the aforementioned countup library to animate a number. The first order of business is to install countup. Here we use packer to do so; the function call below is identical to running \texttt{npm\ install\ countup\ -\/-save} from the terminal.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{packer}\OperatorTok{::}\KeywordTok{npm_install}\NormalTok{(}\StringTok{"countup"}\NormalTok{, }\DataTypeTok{scope =} \StringTok{"prod"}\NormalTok{) }
\end{Highlighting}
\end{Shaded}

We will not need the \texttt{header.js} file. We can delete it and in its stead create another file called \texttt{count.js}. This file will include a function that uses countup to animate the numbers. It should accept 1) the id of the element where countup should be used, and 2) the value that countup should animate. This function called \texttt{counter} is, at the end of the file, exported\index{export}.

\begin{Shaded}
\begin{Highlighting}[]
\ImportTok{import} \OperatorTok{\{}\NormalTok{ CountUp }\OperatorTok{\}} \ImportTok{from} \StringTok{'countup.js'}\OperatorTok{;}

\KeywordTok{function} \AttributeTok{counter}\NormalTok{(id}\OperatorTok{,}\NormalTok{ value)}\OperatorTok{\{}
  \KeywordTok{var}\NormalTok{ countUp }\OperatorTok{=} \KeywordTok{new} \AttributeTok{CountUp}\NormalTok{(id}\OperatorTok{,}\NormalTok{ value)}\OperatorTok{;}
  \VariableTok{countUp}\NormalTok{.}\AttributeTok{start}\NormalTok{()}\OperatorTok{;}
\OperatorTok{\}}

\ImportTok{export} \OperatorTok{\{}\NormalTok{ counter }\OperatorTok{\};}
\end{Highlighting}
\end{Shaded}

We need to add the import statement to bring in the \texttt{counter} function and run it in the \texttt{renderValue} method. Packer also added the htmlwidgets external dependency\index{dependency}, which is imported below with \texttt{import\ \textquotesingle{}widgets\textquotesingle{}}.

Because we left the \emph{R function} \texttt{countup} untouched, we have to use the default \texttt{message} variable it accepts. Ideally, this argument in the R function should be renamed to something more adequate.

\begin{Shaded}
\begin{Highlighting}[]
\ImportTok{import} \StringTok{'widgets'}\OperatorTok{;}
\ImportTok{import} \OperatorTok{\{}\NormalTok{ counter }\OperatorTok{\}} \ImportTok{from} \StringTok{'../modules/count.js'}\OperatorTok{;} 

\VariableTok{HTMLWidgets}\NormalTok{.}\AttributeTok{widget}\NormalTok{(}\OperatorTok{\{}

  \DataTypeTok{name}\OperatorTok{:} \StringTok{'countup'}\OperatorTok{,}

  \DataTypeTok{type}\OperatorTok{:} \StringTok{'output'}\OperatorTok{,}

  \DataTypeTok{factory}\OperatorTok{:} \KeywordTok{function}\NormalTok{(el}\OperatorTok{,}\NormalTok{ width}\OperatorTok{,}\NormalTok{ height) }\OperatorTok{\{}

    \CommentTok{// }\AlertTok{TODO}\CommentTok{: define shared variables for this instance}

    \ControlFlowTok{return} \OperatorTok{\{}

      \DataTypeTok{renderValue}\OperatorTok{:} \KeywordTok{function}\NormalTok{(x) }\OperatorTok{\{}

        \AttributeTok{counter}\NormalTok{(}\VariableTok{el}\NormalTok{.}\AttributeTok{id}\OperatorTok{,} \VariableTok{x}\NormalTok{.}\AttributeTok{message}\NormalTok{)}\OperatorTok{;}

      \OperatorTok{\},}

      \DataTypeTok{resize}\OperatorTok{:} \KeywordTok{function}\NormalTok{(width}\OperatorTok{,}\NormalTok{ height) }\OperatorTok{\{}

        \CommentTok{// }\AlertTok{TODO}\CommentTok{: code to re-render the widget with a new size}

      \OperatorTok{\}}

    \OperatorTok{\};}
  \OperatorTok{\}}
\OperatorTok{\}}\NormalTok{)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

Finally, the JavaScript bundle can be generated with \texttt{packer::bundle()}, install the package or run \texttt{devtools::load\_all()}, and test that the widget works!

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{countup}\NormalTok{(}\DecValTok{12345}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

That hopefully is a compelling example to use NPM and webpack to build widgets. It could even be argued that it is easier to set up; dependencies are much more manageable; nothing has to be manually downloaded; it will be easier to update them in the future, etc.

\hypertarget{packer-adv-shiny-vue}{%
\section{Shiny with Vue and Bootstrap 4}\label{packer-adv-shiny-vue}}

In this example, we create a Shiny application that uses \href{https://vuejs.org/}{Vue.js}\index{Vue} and Bootstrap 4 in the front end. As you may know, Shiny ships with Bootstrap version 3, not 4 (the latest at the time of writing this).

\hypertarget{packer-adv-shiny-vue-setup}{%
\subsection{Setup}\label{packer-adv-shiny-vue-setup}}

If you prefer using \href{https://reactjs.org/}{React}, know that it is also supported by webpack and packer. Vue is a framework to create user interfaces that, like React, make much of the front end work much more straightforward. It reduces the amount of code one has to write, simplifies business logic, enables reactivity, and much more.

Since packer only allows placing scaffolds in R packages, the way one can build Shiny applications is using the golem package. Golem is an opinionated framework to build applications \emph{as R packages.} Writing Shiny applications as R packages brings many of the advantages that packages have to Shiny applications: ease of installation, unit testing, dependency management, etc.

\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{install.packages}\NormalTok{(}\StringTok{"golem"}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

After installing golem from CRAN\index{CRAN}, we can create an application with the \texttt{golem::create\_golem} function; it's very similar to \texttt{usethis::create\_package}, only it prepares a package specifically to build Shiny applications.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{golem}\OperatorTok{::}\KeywordTok{create_golem}\NormalTok{(}\StringTok{"vuer"}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

From within a golem application, one uses a scaffold specifically designed for this with \texttt{scaffold\_golem}. Note that this does not mean other scaffolds will not work, custom Shiny inputs and outputs can also be created with \texttt{scaffold\_input} and \texttt{scaffold\_output}, respectively. The \texttt{scaffold\_golem} function takes two core arguments; \texttt{vue} and \texttt{react}. Setting either of these to \texttt{TRUE} will prepare a scaffold\index{scaffold} specifically designed to support either Vue\index{Vue} or React.

The reason these arguments exist is that webpack requires further configuration that can be tricky to set up manually. Moreover, Vue supports (but does not require) \texttt{.vue} files; these can hold HTML, JavaScript, and CSS. One can think of such files as similar to Shiny modules; they encapsulate a part of the logic of the application for easy modularisation.

When the \texttt{vue} argument is set to \texttt{TRUE} in \texttt{scaffold\_golem}, the function does follow the usual procedure or initialising NPM, creating the various files, and directories, but in addition configures two loaders and the vue\index{Vue} plugin.

Loaders are transformers, they scan files in the \texttt{srcjs} directory and pre-process them. That allows using, for instance, the Babel compiler that will transform the latest version of JavaScript into code that every browser can run. This compiler is very often used, including here, to compile Vue\index{Vue} code. Since Vue allows placing CSS in \texttt{.vue} files, another loader is required; one that will look for CSS and bundle it within the JavaScript file.

Plugins are a feature of webpack that allow extending its functionalities; there is one for Vue\index{Vue}, which the function will install and configure for you.

Also, when creating a scaffold\index{scaffold} for \texttt{vue} or \texttt{react}, one can choose whether to rely on the CDN\index{CDN}, in which case they are installed as developer dependencies, or install them for production, in which case they are included in the bundle. It defaults to using the CDN; this is often advised as the CDN will serve the required files faster.

The scaffold also sets up webpack with Babel, the transpiler that allows writing the latest JavaScript, and ensures it will run on (almost) any web browser. Hence, we can use ES6 notation in places.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{packer}\OperatorTok{::}\KeywordTok{scaffold_golem}\NormalTok{(}\DataTypeTok{vue =} \OtherTok{TRUE}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

\begin{verbatim}
── Scaffolding golem ──────────────────────────────────────────
✔ Initialiased npm
✔ webpack, webpack-cli, webpack-merge installed with scope dev
✔ Added npm scripts
✔ Created srcjs directory
✔ Created srcjs/config directory
✔ Created webpack config files

── Adding files to '.gitignore' and '.Rbuildignore' ──

✔ Setting active project to '/Projects/vuer'
✔ Adding '^srcjs$' to '.Rbuildignore'
✔ Adding '^node_modules$' to '.Rbuildignore'
✔ Adding '^package\\.json$' to '.Rbuildignore'
✔ Adding '^package-lock\\.json$' to '.Rbuildignore'
✔ Adding '^webpack\\.dev\\.js$' to '.Rbuildignore'
✔ Adding '^webpack\\.prod\\.js$' to '.Rbuildignore'
✔ Adding '^webpack\\.common\\.js$' to '.Rbuildignore'
✔ Adding 'node_modules' to '.gitignore'

── Vue loader, plugin & dependency ──

✔ babel-loader installed with scope dev
✔ Added loader rule for 'babel-loader'
✔ @babel/core, @babel/preset-env installed with scope dev
✔ vue installed with scope dev
✔ vue-loader, vue-template-compiler installed with scope dev
✔ Added loader rule for 'vue-loader' and 'vue-template-compiler'
✔ style-loader, css-loader installed with scope dev
✔ Added loader rule for 'style-loader' and 'css-loader'
✔ Created R/vue_cdn.R containing `vueCDN()` function
✔ Added alias to srcjs/config/misc.json

── Babel config file ──

✔ Created '.babelrc'
✔ Adding '^\\.babelrc$' to '.Rbuildignore'

── Template files ──

✔ Added srcjs/Home.vue template
! Place the following in your shiny ui:
tagList(
  vueCDN(),
  div(id = "app"),
  tags$script(src = "www/index.js")
)

── Scaffold built ──

ℹ Run `bundle` to build the JavaScript files
\end{verbatim}

Note the first instruction that was printed in the console; it states a \texttt{tagList} must be placed in the Shiny UI of the application. It imports the Vue\index{Vue} dependency via the CDN with \texttt{vueCDN()}, which is a function created by packer, creates a \texttt{\textless{}DIV\textgreater{}} with an id attribute of \texttt{app} that will be used as root of the Vue application; where the application generated by Vue will be placed. It also imports the bundled JavaScript (\texttt{index.js}). So let us place that in the Shiny UI, which is in the \texttt{R/app\_ui.R} file.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{app_ui <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(request) \{}
  \KeywordTok{tagList}\NormalTok{(}
    \KeywordTok{golem_add_external_resources}\NormalTok{(),}
    \KeywordTok{fluidPage}\NormalTok{(}
      \KeywordTok{tagList}\NormalTok{(}
        \KeywordTok{vueCDN}\NormalTok{(),}
        \KeywordTok{div}\NormalTok{(}\DataTypeTok{id =} \StringTok{"app"}\NormalTok{),}
\NormalTok{        tags}\OperatorTok{$}\KeywordTok{script}\NormalTok{(}\DataTypeTok{src =} \StringTok{"www/index.js"}\NormalTok{)}
\NormalTok{      )}
\NormalTok{    )}
\NormalTok{  )}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

To ensure all is correct up to this point we can test the application; the JavaScript can be bundled with \texttt{packer::bundle()} then the app tested by running \texttt{run\_app()}.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{packer}\OperatorTok{::}\KeywordTok{bundle}\NormalTok{()}
\NormalTok{devtools}\OperatorTok{::}\KeywordTok{load_all}\NormalTok{()}
\KeywordTok{run_app}\NormalTok{()}
\end{Highlighting}
\end{Shaded}

\hypertarget{packer-adv-shiny-vue-bs4}{%
\subsection{Bootstrap 4 Installation}\label{packer-adv-shiny-vue-bs4}}

Next, we can install Bootstrap 4; we'll use \href{https://bootstrap-vue.org/}{bootstrap-vue} which contains a lot of Bootstrap 4 components for Vue\index{Vue}. We won't be using any CDN here, so we install those dependencies as production.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{packer}\OperatorTok{::}\KeywordTok{npm_install}\NormalTok{(}\StringTok{"bootstrap-vue"}\NormalTok{, }\StringTok{"bootstrap"}\NormalTok{, }\DataTypeTok{scope =} \StringTok{"prod"}\NormalTok{)}
\end{Highlighting}
\end{Shaded}

This will cause some issues though, as the Shiny application will have two different versions of Bootstrap, the default version 3 and version 4 from the bundle. We need to remove Bootstrap 3.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{app_ui <-}\StringTok{ }\ControlFlowTok{function}\NormalTok{(request) \{}
  \KeywordTok{tagList}\NormalTok{(}
    \KeywordTok{golem_add_external_resources}\NormalTok{(),}
    \CommentTok{# remove default bootstrap 3}
\NormalTok{    htmltools}\OperatorTok{::}\KeywordTok{suppressDependencies}\NormalTok{(}\StringTok{"bootstrap"}\NormalTok{),}
    \KeywordTok{fluidPage}\NormalTok{(}
      \KeywordTok{tagList}\NormalTok{(}
        \KeywordTok{vueCDN}\NormalTok{(),}
        \KeywordTok{div}\NormalTok{(}\DataTypeTok{id =} \StringTok{"app"}\NormalTok{),}
\NormalTok{        tags}\OperatorTok{$}\KeywordTok{script}\NormalTok{(}\DataTypeTok{src =} \StringTok{"www/index.js"}\NormalTok{)}
\NormalTok{      )}
\NormalTok{    )}
\NormalTok{  )}
\NormalTok{\}}
\end{Highlighting}
\end{Shaded}

\hypertarget{packer-adv-shiny-vue-code}{%
\subsection{Vue Code}\label{packer-adv-shiny-vue-code}}

Let us now explore the contents of \texttt{srcjs} and code a basic functionality. It's relatively straightforward; it consists of two files. The first, \texttt{index.js}, creates the Vue\index{Vue} application and places it in the \texttt{div(id\ =\ "app")}. The code for the app itself is in a \texttt{.vue} file, which it imports with \texttt{import\ App\ from\ "./Home.vue";}.

\begin{Shaded}
\begin{Highlighting}[]
\ImportTok{import}\NormalTok{ Vue }\ImportTok{from} \StringTok{"vue"}\OperatorTok{;}
\ImportTok{import}\NormalTok{ App }\ImportTok{from} \StringTok{"./Home.vue"}\OperatorTok{;}

\KeywordTok{new} \AttributeTok{Vue}\NormalTok{(}\OperatorTok{\{}
  \DataTypeTok{el}\OperatorTok{:} \StringTok{"#app"}\OperatorTok{,}
  \DataTypeTok{template}\OperatorTok{:} \StringTok{"<App/>"}\OperatorTok{,}
  \DataTypeTok{components}\OperatorTok{:} \OperatorTok{\{}\NormalTok{ App }\OperatorTok{\}}
\OperatorTok{\}}\NormalTok{)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

The first order of business is to import the Bootstrap dependencies\index{dependency} that were installed and ``use'' them in the application. We don't explain this in great detail here as much of it is specific to Vue and is thus outside the scope of this book.

\begin{Shaded}
\begin{Highlighting}[]
\ImportTok{import}\NormalTok{ Vue }\ImportTok{from} \StringTok{"vue"}\OperatorTok{;}
\ImportTok{import} \OperatorTok{\{}\NormalTok{ BootstrapVue}\OperatorTok{,}\NormalTok{ IconsPlugin }\OperatorTok{\}} \ImportTok{from} \StringTok{'bootstrap-vue'}
\CommentTok{// import dependencies}
\ImportTok{import} \StringTok{'bootstrap/dist/css/bootstrap.css'}
\ImportTok{import} \StringTok{'bootstrap-vue/dist/bootstrap-vue.css'}
\ImportTok{import}\NormalTok{ App }\ImportTok{from} \StringTok{"./Home.vue"}\OperatorTok{;}

\CommentTok{// attach dependencies}
\VariableTok{Vue}\NormalTok{.}\AttributeTok{use}\NormalTok{(BootstrapVue)}
\VariableTok{Vue}\NormalTok{.}\AttributeTok{use}\NormalTok{(IconsPlugin)}

\KeywordTok{new} \AttributeTok{Vue}\NormalTok{(}\OperatorTok{\{}
  \DataTypeTok{el}\OperatorTok{:} \StringTok{"#app"}\OperatorTok{,}
  \DataTypeTok{template}\OperatorTok{:} \StringTok{"<App/>"}\OperatorTok{,}
  \DataTypeTok{components}\OperatorTok{:} \OperatorTok{\{}\NormalTok{ App }\OperatorTok{\}}
\OperatorTok{\}}\NormalTok{)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

The \texttt{Home.vue} file is where the meat of the application is placed. By default, packer creates an app that just displays a message.

\begin{Shaded}
\begin{Highlighting}[]
\OperatorTok{<}\NormalTok{template}\OperatorTok{>}
  \OperatorTok{<}\NormalTok{p}\OperatorTok{>\{\{}\NormalTok{ greeting }\OperatorTok{\}\}}\NormalTok{ powered by Vue}\OperatorTok{!}\NormalTok{</p}\OperatorTok{>}
\NormalTok{</template}\OperatorTok{>}

\OperatorTok{<}\NormalTok{script}\OperatorTok{>}
\VariableTok{module}\NormalTok{.}\AttributeTok{exports} \OperatorTok{=} \OperatorTok{\{}
  \DataTypeTok{data}\OperatorTok{:} \KeywordTok{function}\NormalTok{() }\OperatorTok{\{}
    \ControlFlowTok{return} \OperatorTok{\{}
      \DataTypeTok{greeting}\OperatorTok{:} \StringTok{"Shiny"}
    \OperatorTok{\};}
  \OperatorTok{\}}
\OperatorTok{\};}
\NormalTok{</script}\OperatorTok{>}

\OperatorTok{<}\NormalTok{style scoped}\OperatorTok{>}
\NormalTok{p }\OperatorTok{\{}
\NormalTok{  font}\OperatorTok{-}\DataTypeTok{size}\OperatorTok{:}\NormalTok{ 2em}\OperatorTok{;}
\NormalTok{  text}\OperatorTok{-}\DataTypeTok{align}\OperatorTok{:}\NormalTok{ center}\OperatorTok{;}
\OperatorTok{\}}
\NormalTok{</style}\OperatorTok{>}
\end{Highlighting}
\end{Shaded}

Below we make changes to the application, so it features a Boostrap 4 text input. After having entered some text and hitting enter the text entered is displayed below and cleared from the input. We also provide a button that sends the input data to the R server.

\begin{Shaded}
\begin{Highlighting}[]
\OperatorTok{<}\NormalTok{template}\OperatorTok{>}
  \OperatorTok{<}\NormalTok{div}\OperatorTok{>}
    \OperatorTok{<}\NormalTok{b}\OperatorTok{-}\NormalTok{form}\OperatorTok{-}\NormalTok{input }
\NormalTok{      v}\OperatorTok{-}\NormalTok{model}\OperatorTok{=}\StringTok{"inputText"} 
\NormalTok{      placeholder}\OperatorTok{=}\StringTok{"Enter your name"} 
\NormalTok{      @}\VariableTok{keyup}\NormalTok{.}\AttributeTok{enter}\OperatorTok{=}\StringTok{"processText"}\OperatorTok{>}
\NormalTok{    </b}\OperatorTok{-}\NormalTok{form}\OperatorTok{-}\NormalTok{input}\OperatorTok{>}
    \OperatorTok{<}\NormalTok{b}\OperatorTok{-}\NormalTok{button }
\NormalTok{      @click}\OperatorTok{=}\StringTok{"processText"} 
\NormalTok{      variant}\OperatorTok{=}\StringTok{"outline-primary"}\OperatorTok{>}
\NormalTok{      Button}
\NormalTok{    </b}\OperatorTok{-}\NormalTok{button}\OperatorTok{>}
    \OperatorTok{<}\NormalTok{h2}\OperatorTok{>}\NormalTok{Your name is }\OperatorTok{\{\{}\NormalTok{ text }\OperatorTok{\}\}}\NormalTok{</h2}\OperatorTok{>}
\NormalTok{  </div}\OperatorTok{>}
\NormalTok{</template}\OperatorTok{>}

\OperatorTok{<}\NormalTok{script}\OperatorTok{>}
\VariableTok{module}\NormalTok{.}\AttributeTok{exports} \OperatorTok{=} \OperatorTok{\{}
  \DataTypeTok{data}\OperatorTok{:} \KeywordTok{function}\NormalTok{() }\OperatorTok{\{}
    \ControlFlowTok{return} \OperatorTok{\{}
      \DataTypeTok{text}\OperatorTok{:} \StringTok{''}\OperatorTok{,}
      \DataTypeTok{inputText}\OperatorTok{:} \StringTok{''}
    \OperatorTok{\};}
  \OperatorTok{\},}
  \DataTypeTok{methods}\OperatorTok{:} \OperatorTok{\{}
    \DataTypeTok{processText}\OperatorTok{:} \KeywordTok{function}\NormalTok{()}\OperatorTok{\{}
      \KeywordTok{this}\NormalTok{.}\AttributeTok{text} \OperatorTok{=} \KeywordTok{this}\NormalTok{.}\AttributeTok{inputText} \CommentTok{// set text var}
      \VariableTok{Shiny}\NormalTok{.}\AttributeTok{setInputValue}\NormalTok{(}\StringTok{'text'}\OperatorTok{,} \KeywordTok{this}\NormalTok{.}\AttributeTok{text}\NormalTok{)}\OperatorTok{;}
      \KeywordTok{this}\NormalTok{.}\AttributeTok{inputText} \OperatorTok{=} \StringTok{''} \CommentTok{// remove input once entered}
    \OperatorTok{\}}
  \OperatorTok{\}}
\OperatorTok{\};}
\NormalTok{</script}\OperatorTok{>}
\end{Highlighting}
\end{Shaded}

Finally, we can bundle the JavaScript, and run the application to obtain Figure \ref{fig:vue-bs4}.

\begin{Shaded}
\begin{Highlighting}[]
\NormalTok{packer}\OperatorTok{::}\KeywordTok{bundle}\NormalTok{()}
\NormalTok{devtools}\OperatorTok{::}\KeywordTok{load_all}\NormalTok{()}
\KeywordTok{run_app}\NormalTok{()}
\end{Highlighting}
\end{Shaded}

\begin{figure}[H]

{\centering \includegraphics[width=1\linewidth]{images/vue-bs4} 

}

\caption{Shiny application with Vue and Bootstrap 4}\label{fig:vue-bs4}
\end{figure}

Note how little code was written in order to provide these functionalities. It is one of the most powerful features of frameworks like Vue\index{Vue} and React. They are not necessary; this could have been coded in vanilla JavaScript, but would admittedly require much more (difficult to read) code.

\hypertarget{part-closing-remarks}{%
\part{Closing Remarks}\label{part-closing-remarks}}

\hypertarget{conclusion}{%
\chapter{Conclusion}\label{conclusion}}

The book covered a few topics and introduced many concepts probably new to many; these are sometimes difficult to fully understand at first and will likely require some more exploring. So here, we wrap up with some heartening thoughts to encourage the reader to persevere, as much of what was covered in the book requires practice to be fully comprehended.

\hypertarget{conclusion-performances}{%
\section{Performances}\label{conclusion-performances}}

As mentioned in the opening of this book some of the code presented is not entirely optimal as we need to make use of R as much as possible to limit any confusion caused by the fresh-to-the-eyes JavaScript code. In places, this involves making use of R where it is in fact not needed, namely within Shiny applications where data is sent from the front end to R, only to be sent back to JavaScript again. For instance, when the click of a button triggers something in the Shiny UI but uses the server as an intermediary, oftentimes it is not necessary to involve the server.

This, though, has little impact on performances in most cases, and can be improved upon by not involving R in the process and handling everything in the front end with JavaScript. This was judged outside the scope of the book as it focuses on interactions between the two languages. Nonetheless, somewhat interestingly, the book covered all the code necessary to do so, only not in the same section or chapter. It might, therefore, take some practice to make the connection.

\begin{Shaded}
\begin{Highlighting}[]
\CommentTok{// toggle an input at the click of a button}
\AttributeTok{$}\NormalTok{(}\StringTok{'#button'}\NormalTok{).}\AttributeTok{on}\NormalTok{(}\StringTok{'click'}\OperatorTok{,} \KeywordTok{function}\NormalTok{()}\OperatorTok{\{}
  \AttributeTok{$}\NormalTok{(}\StringTok{'#input'}\NormalTok{).}\AttributeTok{toggle}\NormalTok{()}\OperatorTok{;}
\OperatorTok{\}}\NormalTok{)}\OperatorTok{;}
\end{Highlighting}
\end{Shaded}

Note, however, that placing much of the business logic server-side rather than on the front end might create more secure applications since said logic remains internal and cannot be interfered with.

\hypertarget{conclusion-trial-and-error}{%
\section{Trial and Error}\label{conclusion-trial-and-error}}

We hope the book demonstrated how well JavaScript works with R, as well as how much of a difference it has the potential to have on your data science projects. Making JavaScript work \emph{for R} is fascinating because they are so far removed from one another; while one excels at data wrangling and statistics, the other runs in the browser and focuses on aesthetics and functionalities of web pages.

However, being so different, JavaScript introduces numerous concepts likely to be new to many R developers. The only way one can truly grasp how it all works, and become at ease with using custom JavaScript code in Shiny applications and packages, is to practice. Repeated trial and error is fundamental to approaching new programming languages and notions.

Some small exercises were scattered at the end of significant parts of the book; you are encouraged to attempt some of them. Like interactive visualisations? Try to build one for a straightforward library!

\hypertarget{conclusion-ux}{%
\section{Functionality and UX}\label{conclusion-ux}}

A lot of JavaScript in the browser is about designing user experiences and better functionalities for users of your data product---never overlook those.

We don't say of a chart with pleasing aesthetics ``that's just a pretty plot''; a great chart does a better job of communicating insights, and the same is true of many other data products, including web applications. Hopefully, the learnings contained in this book will help you create much more engaging and compelling products thanks to JavaScript.

Sadly, in the fields where R is popular, things like aesthetics, or great user experience are perceived as superfluous. You might be told that ``the only thing that matters is the analysis or the model''; anything else is often seen as make-up to cover up flawed science. This could not be further from the truth. First, put to rest the false dichotomy that it's either a great front end or a great back end; both can (and must) be done. Second, while it could be said that spending two hours looking for a fun colour palette for a chart is ``a waste of time,'' spending the same amount of time developing new JavaScript functionalities to allow users to interrogate your model better, or visualise (and therefore understand) the outcome of an analysis is not. Also, if your visualisations and web applications are engaging, users will gladly spend more time clicking away, interrogating results, and using your product.

\bibliography{book.bib,packages.bib}

\backmatter
\printindex

\end{document}
